Kotlin之基本语法详解手机开发

在今年Google IO大会上Google已经明确kotlin作为为Android第一官方语言的地位。我相信Google的决意,就像当初毫不犹豫的抛弃eclipse转向as,kotlin已经是不可避免的大势所趋了。再加上Kotlin与java代码完全兼容,所以从Java转向Kotlin是一件很容易的事情。Kotlin语法简单,它融合了当前多种语言的优势,可以是一门明星语言。

下面就Kotlin的一些基本语法做一个讲解。

一个源文件往往以包声明开始:源文件的所有内容(比如类和函数)都被包声明并包括。

package foo.bar 
 
fun bza() {} 
 
class Goo {}

在上面的例子中, bza() 的全名应该是 foo.bar.bza ,Goo 的全名是 foo.bar.Goo。如果没有指定包名,那这个文件的内容就从属于一个默认的 “default” 包。

Imports

在源文件中,除了模块中默认导入的包,每个文件也可以有它自己的导入指令。比如:

import foo.Bar 

如果不指定特定的文件,那么可以使用*导入范围内的所有可用的内容 (包,类,对象,等等)。比如:

import foo.*   //foo 中的所有内容

如果命名有冲突,我们还可以使用 as 关键字局部重命名解决冲突。

import foo.Bar // Bar 可以使用 
import bar.Bar as bBar // bBar 代表 'bar.Bar'

函数

函数声明

在 kotlin 中用关键字 fun 声明函数:

fun double(x: Int): Int { 
 
}

参数

函数参数用 Pascal 符号定义,格式形如:name:type,参数之间用逗号隔开,每个参数必须指明类型。

fun powerOf(number: Int, exponent: Int) { 
... 
}

函数参数可以设置默认值,默认值可以通过在type类型后使用=号进行赋值,当参数被忽略时会使用默认值,这样做的好处是可以减少重载。

fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size() ) { 
... 
}

函数调用

在函数内部可以直接使用函数,比如:

val result = double(2) 

如果在其他类需要调用调用成员函数:

Sample().foo() // 创建Sample类的实例,调用foo方法

中缀符号

在满足如下条件时:它们是成员函数或者是扩展函数,只有一个参数 使用infix关键词进行标记。函数可以通过中缀符号进行调用。比如:

//给 Int 定义一个扩展方法 
infix fun Int.shl(x: Int): Int { 
... 
} 
 
1 shl 2 //用中缀注解调用扩展函数 
 
1.shl(2)

Unit类型

如果函数不会返回任何有用值,那么他的返回类型就是 Unit 。Unit 是一个只有唯一值Unit的类型,这个值并不需要被直接返回,相当于Java的Void。

fun printHello(name: String?): Unit { 
    if (name != null) 
        println("Hello ${name}") 
    else 
        println("Hi there!") 
    // `return Unit` or `return` is optional 
}

Unit 返回值也可以省略,例如下面这样:

fun printHello(name: String?) { 
    ... 
}

单表达式函数

当函数只返回单个表达式时,大括号可以省略,并在 = 后面定义函数体:

fun double(x: Int): Int = x*2

如果进一步精简,还可以写成如下的方式。

fun double(x: Int) = x * 2

变长参数

函数的参数(通常是最后一个参数)可以用 vararg 修饰符进行标记,标记后,允许给函数传递可变长度的参数:

fun asList<T>(vararg ts: T): List<T> { 
    val result = ArrayList<T>() 
    for (t in ts) 
        result.add(t) 
    return result 
} 
 
 
val list = asList(1, 2, 3)

可变函数只有一个参数可以被标注为 vararg 。加入vararg并不是列表中的最后一个参数,那么后面的参数需要通过命名参数语法进行传值,再或者如果这个参数是函数类型,就需要通过lambda法则。

当调用变长参数的函数时,我们可以一个一个的传递参数,比如:

asList(1, 2, 3)

或者我们要传递一个 array 的内容给函数,那么就可以使用 * 前缀操作符:

val a = array(1, 2, 3) 
val list = asList(-1, 0, *a, 4)

函数范围

Kotlin 中可以在文件顶级声明函数,这就意味者你不用像在Java,C#或是Scala一样创建一个类来持有函数。除了顶级函数,Kotlin 函数可以声明为局部的,作为成员函数或扩展函数。

Kotlin 支持局部函数,比如在一个函数包含另一函数。

fun dfs(graph: Graph) { 
  fun dfs(current: Vertex, visited: Set<Vertex>) { 
    if (!visited.add(current)) return 
    for (v in current.neighbors) 
      dfs(v, visited) 
  } 
 
  dfs(graph.vertices[0], HashSet()) 
}

当然,局部函数可以访问外部函数的局部变量(比如闭包)。

fun dfs(graph: Graph) { 
    val visited = HashSet<Vertex>() 
    fun dfs(current: Vertex) { 
        if (!visited.add(current)) return  
        for (v in current.neighbors) 
            dfs(v) 
    } 
    dfs(graph.vertices[0]) 
}

局部函数甚至可以返回到外部函数。

fun reachable(from: Vertex, to: Vertex): Boolean { 
    val visited = HashSet<Vertex>() 
    fun dfs(current: Vertex) { 
        if (current == to) return@reachable true 
        if (!visited.add(current)) return 
        for (v  in current.neighbors) 
            dfs(v) 
    } 
    dfs(from) 
    return false 
}

泛型函数

Kotlin和Java一样,还支持泛型函数。

fun sigletonArray<T>(item: T): Array<T> { 
    return Array<T>(1, {item}) 
}

尾递归函数

Kotlin 支持函数式编程的尾递归。这个允许一些算法可以通过循环而不是递归解决问题,从而避免了栈溢出。当函数被标记为 tailrec 时,编译器会优化递归,并用高效迅速的循环代替它。

tailrec fun findFixPoint(x: Double = 1.0): Double  
    = if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))

这段代码计算的是数学上的余弦不动点。Math.cos 从 1.0 开始不断重复,直到值不变为止,结果是 0.7390851332151607。上面的代码等效于:

private fun findFixPoint(): Double { 
    var x = 1.0 
    while (true) { 
        val y = Math.cos(x) 
        if ( x == y ) return y 
        x = y 
    } 
}

注:使用 tailrec 修饰符必须在最后一个操作中调用自己。在递归调用代码后面是不允许有其它代码的,并且也不可以在 try/catch/finall 块中进行使用。当前的尾递归只在 JVM 的后端中可以用。

字符串

fun main(args: Array<String>) { 
  var a = 1 
  // 使用变量名作为模板: 
  val s1 = "a is $a" 
 
  a = 2 
  // 使用表达式作为模板: 
  val s2 = "${s1.replace("is", "was")}, but now is $a" 
  println(s2) 
}

条件表达式

fun maxOf(a: Int, b: Int): Int { 
    if (a > b) { 
        return a 
    } else { 
        return b 
    } 
} 
 
fun main(args: Array<String>) { 
    println("max of 0 and 42 is ${maxOf(0, 42)}") 
}

上面的表达式可简写为:

fun maxOf(a: Int, b: Int) = if (a > b) a else b 
 
fun main(args: Array<String>) { 
    println("max of 0 and 42 is ${maxOf(0, 42)}") 
}

值检查与自动转换

使用 is 操作符检查一个表达式是否是某个类型的实例。如果对不可变的局部变量或属性进行过了类型检查,就没有必要明确转换:

fun getStringLength(obj: Any): Int? { 
  if (obj is String) { 
    // obj 将会在这个分支中自动转换为 String 类型 
    return obj.length 
  } 
 
  // obj 在种类检查外仍然是 Any 类型 
  return null 
} 
 
 
fun main(args: Array<String>) { 
  fun printLength(obj: Any) { 
    println("'$obj' string length is ${getStringLength(obj) ?: "... err, not a string"} ") 
  } 
  printLength("Incomprehensibilities") 
  printLength(1000) 
  printLength(listOf(Any())) 
}

for循环

Kotlin简化了for循环的方式,例如:

fun main(args: Array<String>) { 
  val items = listOf("apple", "banana", "kiwi") 
  for (item in items) { 
    println(item) 
  } 
  //或者使用下面的方式 
  //for (index in items.indices) { 
  // println("item at $index is ${items[index]}") 
  //} 
}

while 循环

fun main(args: Array<String>) { 
  val items = listOf("apple", "banana", "kiwi") 
  var index = 0 
  while (index < items.size) { 
    println("item at $index is ${items[index]}") 
    index++ 
  } 
}

ranges

检查 in 操作符检查数值是否在某个范围内:

fun main(args: Array<String>) { 
  val x = 10 
  val y = 9 
  if (x in 1..y+1) { 
      println("fits in range") 
  } 
}

检查数值是否在范围外:

fun main(args: Array<String>) { 
  val list = listOf("a", "b", "c") 
 
  if (-1 !in 0..list.lastIndex) { 
    println("-1 is out of range") 
  } 
  if (list.size !in list.indices) { 
    println("list size is out of valid list indices range too") 
  } 
}

在范围内迭代:

fun main(args: Array<String>) { 
  for (x in 1..5) { 
    print(x) 
  } 
}

或者使用步进:

fun main(args: Array<String>) { 
  for (x in 1..10 step 2) { 
    print(x) 
  } 
  for (x in 9 downTo 0 step 3) { 
    print(x) 
  } 
}

集合

对一个集合进行迭代:

fun main(args: Array<String>) { 
  val items = listOf("apple", "banana", "kiwi") 
  for (item in items) { 
    println(item) 
  } 
}

使用 in 操作符检查集合中是否包含某个对象。

fun main(args: Array<String>) { 
  val items = setOf("apple", "banana", "kiwi") 
  when { 
    "orange" in items -> println("juicy") 
    "apple" in items -> println("apple is fine too") 
  } 
}

使用lambda表达式过滤和映射集合:

fun main(args: Array<String>) { 
  val fruits = listOf("banana", "avocado", "apple", "kiwi") 
  fruits 
    .filter { it.startsWith("a") } 
    .sortedBy { it } 
    .map { it.toUpperCase() } 
    .forEach { println(it) } 
}

附:高阶函数和lambda表达式

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/5525.html

(0)
上一篇 2021年7月16日
下一篇 2021年7月16日

相关推荐

发表回复

登录后才能评论