Kotlin学习之旅-第四天
今天的主题是:函数与Lambda表达式
前言
函数
Kotlin里面的函数其实在之前的学习中已经见过了,通过 fun 关键字来标识
1 | fun double(x: Int): Int { |
默认参数
除了一般的使用 x: Int 这种方式定义参数,我们也可以使用默认参数的方式,这种方式可以有效减少重载方法的数量
1 | fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size) {...} |
- off是默认值为0的Int类型参数
- len是默认值为b.size的Int类型参数
命名参数
在Java里面,我们调用具有多个参数的方法,是无法直接看到每个参数的意思的,例如:
1 | private void reformat(String str, Boolean normalizeCase, Boolean upperCaseFirstLetter, Boolean, divideByCamelHumps, Char wordSeparator){ |
在Kotlin里面,我们可以在调用的时候给参数加个名字,就像:
1 | fun reformat(str: String, |
这样代码的可读性更高,在多个参数的时候能清晰看到每个参数的作用
返回Unit的函数
前面写的几个方法都有返回值,那么如果要像Java里面一样返回void,在kotlin要怎么写呢?
1 | fun printHello(name: String?): Unit { |
通过 Unit 关键字表示返回 Unit类型,他的作用类似于Java里面的void,在Kotlin里面,Unit返回类型是可以省略的。
中缀表示法
标有 infix 关键字的函数也可以使用中缀表示法(忽略该调用的点与圆括号)调用。中缀函数必须满足以下要求:
1 | infix fun Int.shl(x: Int): Int { …… } |
中缀函数调用的优先级低于算术操作符、类型转换以及
rangeTo
操作符。 以下表达式是等价的:
1 shl 2 + 3
与1 shl (2 + 3)
0 until n * 2
与0 until (n * 2)
xs union ys as Set<*>
与xs union (ys as Set<*>)
另一方面,中缀函数调用的优先级高于布尔操作符
&&
与||
、is-
与in-
检测以及其他一些操作符。这些表达式也是等价的:
a && b xor c
与a && (b xor c)
a xor b in c
与(a xor b) in c
完整的优先级层次结构请参见其语法参考。
Lambda 表达式
关于Lambda表达式这部分,从Java8就开始支持了,在实际开发中也会经常用到,但对我来说还是太抽象了,一直都不太理解,因此这一块我是参照官方文档来写的。如果有好的学习资料,欢迎大家留言~
lambda 表达式与匿名函数是“函数字面值”,即未声明的函数, 但立即做为表达式传递。考虑下面的例子:
1 | max(strings, { a, b -> a.length < b.length }) |
函数 max
是一个高阶函数,它接受一个函数作为第二个参数。 其第二个参数是一个表达式,它本身是一个函数,即函数字面值,它等价于以下命名函数:
1 | fun compare(a: String, b: String): Boolean = a.length < b.length |
从上面的例子看来,其实Lambda就是一种函数的表达方式,这个函数还未声明,但是通过Lambda表达式可以直接调用,只要掌握了语法,就能很方便的写出来了。
Lambda 表达式语法
Lambda 表达式的完整语法形式如下:
1 | val sum = { x: Int, y: Int -> x + y } |
lambda 表达式总是括在花括号中, 完整语法形式的参数声明放在花括号内,并有可选的类型标注, 函数体跟在一个 ->
符号之后。如果推断出的该 lambda 的返回类型不是 Unit
,那么该 lambda 主体中的最后一个(或可能是单个)表达式会视为返回值。
如果我们把所有可选标注都留下,看起来如下:
1 | val sum: (Int, Int) -> Int = { x, y -> x + y } |
把上面的官方文档说明翻译一下,就是:
1 | 1.lambda表达式总是括在花括号中 |
因此上面的例子翻译一下,就是:
1 | 1.{ x, y -> x + y } 为lambda表达式 |
it
:单个参数的隐式名称
一个 lambda 表达式只有一个参数是很常见的。
如果编译器自己可以识别出签名,也可以不用声明唯一的参数并忽略 ->
。 该参数会隐式声明为 it
:
1 | ints.filter { it > 0 } // 这个字面值是“(it: Int) -> Boolean”类型的 |
几个Tips
Lambda表达式可以传递给一个高阶函数当做参数
1
2
3
4
5
6
7
8
9
10fun <T, R> Collection<T>.fold(
initial: R,
combine: (acc: R, nextElement: T) -> R
): R {
var accumulator: R = initial
for (element: T in this) {
accumulator = combine(accumulator, element)
}
return accumulator
}fold这个函数的第二个参数是 combine(R, T),同样是一个函数,他的返回值会作为fold的参数,那么flod就是一个高阶函数,而combine里面可以使用Lambda表达式~
如果函数的最后一个参数是一个函数,并且你传递一个 lambda 表达式作为相应的参数,你可以在圆括号之外指定它
例如:
1
2
3val product = items.fold(1, { acc, e -> acc * e })
=>
val product = items.fold(1) { acc, e -> acc * e }如果一个函数的参数只有一个,并且参数也是一个函数,那么可以省略圆括号
例如:
1
2
3run ({ println("...") })
=>
run { println("...") }
总结
由于Kotlin里面Lambda表达式的使用还是很多的,所以建议大家多去看看其他的博客,因为我觉得官方文档对于没接触过Lambda的初学者来说还是太难懂了一点。
Day 4 - Learn Kotlin Trip, Completed.