Kotlin-函数与lambda

函数

函数应该市不陌生了。在kotlin中使用fun标志函数。标准格式如下,返回值为Unit即空时,省略不写返回类型

1
2
3
fun funName(param: ParamType): ReturnType{

}

说说和java中不一样的。也是其他现代语言基本有的特点

默认参数

允许默认参数值,减少重载函数的数量。调用时后项可以省略

1
2
3
fun test(name: String, age: Int = 10) {

}

具名参数

像php那样,不需要关注参数位置,通过按照按照参数名进行传递参数

1
2
3
4
5
6
7
fun test(name: String, age: Int, mes: String) {

}

fun main() {
test(age = 10, mes = "hello", name ="jack")
}

在参数比较多时,使用具名参数,代码可读性大大提高

可变参数

可变长参数,java中也有,相当于一个变长的数组

1
2
3
4
5
6
fun test(vararg strings: String) {}

fun main() {
test("hello")
test("aa", "bb")
}

单表达式函数

在某些比较简单的函数体,可能是一个表达,此时函数可以进行简写,不需要写括号之类。虽然返回类型可以进行推断,但是为了可读性尽量描述返回类型。

1
fun getMes(a: Int): String = if(a > 3) "a > 3" else "a <= 3"

中缀表示法

标志使用infix的函数是中缀函数

  • 它们必须是成员函数或扩展函数;
  • 它们必须只有一个参数;
  • 其参数不得接受可变数量的参数且不能有默认值。

通过中缀表示可以写出类似自然语言的代码。比如kotlin内部的位操作,

1
2
3
4
5
6
7
infix fun Int.shl(x: Int): Int { …… }

// 用中缀表示法调用该函数
1 shl 2

// 等同于这样
1.shl(2)

局部函数

局部作用域也是可以声明函数的。局部函数可以访问外部函数的变量

1
2
3
4
5
6
7
8
9
fun dfs(graph: Graph) {
fun dfs(current: Vertex, visited: MutableSet<Vertex>) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v, visited)
}

dfs(graph.vertices[0], HashSet())
}

lambda表达式

在kotln的世界,函数使用非常频繁。函数可以作为一个个体进行传递,这就促生了一种用来描述函数类型的语言结构。而根据这个函数类型而描述的语言结构,除了函数,还有lambda。其实二者几乎可以等同。

函数类型

函数类型通常描述为(A,B) -> C这样的结构,即参数加返回值。为了方便阅读,括号尽量加上。

1
2
3
4
val action: ((String) -> String) = { string ->
println("string")
string + "ff"
}

这个就是一个简单的函数类型声明的函数变量,而对于函数变量的赋值的就是括号后面的lambda表达式,第一行用于书写参数,最后一行用于书写返回值。不需要return

而函数和lambda也是可以赋值的。

1
2
3
4
5
6
7
8
9
10
11
val action: ((String) -> String) = { string ->
println("string")
string + "ff"
}

val action2: (String) -> String = action
val action3: (String) -> String = ::test//引用传递

fun test(string: String): String {

}

充分的说明了在kotlin,函数可以像一个变量一样传递使用。这样称之为函数字面值

匿名函数

函数字面值除了lambda可以实例,同样使用匿名函数也是可以实例的

1
2
3
val action4: (String) -> String = fun (string: String):String {
return string + "匿名函数"
}

总结来说,匿名函数和lambda都属于为声明的函数。匿名函数可读较好,lambda较为简洁。

lambda内部存在一个it参数,指代单参数。即在lambda的第一行可以不写参数名,内部使用it代替

1
2
3
4
val action: ((String) -> String) = {
println("string")
it + "ff"
}

结合扩展

既然lambda是一种特殊的函数,当然也是可以使用扩展的,于是也能够获取到this

而且当函数的最后一个参数为函数类型时,可以将lambda写到括号外,如下

1
2
3
4
5
6
7
8
9
10
11
12
fun test(name: String, action: (String -> Unit)) {
println("action before")
action(name)
println("action after")
}

fun main() {
test("jack", {string -> prinln(string + "test action")})//普通写法
test("jack") {string ->
prinln(string + "test action")
}
}

于是就出现了以代码方式书写UI代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
class HTML {
fun body() { …… }
}

fun html(init: HTML.() -> Unit): HTML {
val html = HTML() // 创建接收者对象
html.init() // 将该接收者对象传给该 lambda
return html
}

html { // 带接收者的 lambda 由此开始
body() // 调用该接收者对象的一个方法
}

内联函数