一、lambda表达式的语法
{parameter list -> body}
kotlin和java的lambda表达式的语法存在一定程度的差异:
1、kotlin在通常的情况下不允许有return语句,而java则可以有零个或者多个return语句
2、kotlin有隐式的参数it:fun isPrime(n: Int) = n > 1 && (2 until n).none({n % it == 0})
3、lambda的语法格式:fun walkTo(n: Int, action: (Int) -> Unit) = (1..n).forEach(action); 该函数接收的action参数是一个lambda表达式,该表达式接受一个int类型的参数,并且返回值是Unit; 在kotlin中,Unit就是java里面的void
4、kotlin和java的一个共通点是lambda尾随的特性:如上的walkTo可以有如下的调用:walkTo(5) {i -> print(i)}
5、lambda可以作为函数的返回值返回
6、lambda有闭包的概念,可以捕获外部的变量
var factor = 2 val doubled = listOf(1, 2).map {it * factor} factor = 0 doubled.forEach{println(it)}// 输出 2, 4
如上在map的lambda中捕获了factor,此时的factor是2,所以该lambda表达式捕获到了factor等于2的值;接下去虽然factor=0,但是已经过了lambda的区域;虽然最后doubled的输出是在factor=0之后
7、lambda在特殊情况下带return语句
lambda有两种情况可以带return,一种是使用标签的方式,一种是内联的方式
这里说下使用标签的方式
fun invokeWith(n: Int, action: (Int) -> Unit) { println("enter invokeWith $n") action(n) println("exit invokeWith $n") } fun caller() { (1..3).forEach{ i -> invokeWith(i) here@ { println("enter for $it") if (it == 2) { return@here } println("exit for $it") } } println("end of caller") } caller() 如上的输出如下所示 /* enter invokeWith 1 enter for 1 exit for 1 exit invokeWith 1 enter invokeWith 2 enter for 2 exit invokeWith 2 enter invokeWith 3 enter for 3 exit for 3 exit invokeWith 3 end of caller */
通过上面可以看出,return@here只是当it==2时候返回到了这个invokeWith(i)的标记位置,这里return@invokeWith也可以产生相同的效果
8、lambda的内联
lambda的内联是将lambda函数对应的字节复制到所在函数的调用位置,而不止是通过函数指针去调用远处的某个函数
回到第5条关于lambda作为函数返回:内联的lambda函数不能作为返回值返回;因为内联的lambda严格来说不算是有函数指针,返回值没办法返回对应函数内的某块内存
回到第6条关于捕获外部变量:
var factor = 2 val doubledAlso = sequenceOf(1,2).map{it * factor} factor = 0 doubledAlso.forEach{println(it)} 如上的输出是 0 0
由于sequenceOf对应的lambda是内联的,所以这里对应的其实是该lambda的一整块内存,lambda中的factor对应的是外部factor的地址,所以当factor后面设置为0再调用显示的时候则lambda中的factor也是为0
回到第7条关于lambda内部使用return
fun caller1() { (1..3).forEach {i -> println("in foreach for $i") if (i == 2) { return } invokeWith(i) { println("enter for $it") if (it == 2) { return@invokeWith } println("exit for $it") } } } caller1() 调用的结果是: in foreach for 1 enter invokeWith 1 enter for 1 exit for 1 exit invokeWith 1 in foreach for 2
如上所示,在i==2的时候整个forEach的循环调用被return掉了
所以内联其实就是将整个函数拷贝到使用的内联的位置,然后在那里做调用;该位置的return相当于整个函数的return
8、inline对应的noinline
刚才在关于第5点的内容中说的内联lambda不能作为返回值,但是如果是内联函数,但是要作为返回值该如何呢? 这里可以使用noinline
inline fun invokeTwo(n: Int, action1: (Int) -> Unit, noinline action2: (Int) -> Unit): (Int) -> Unit { println("enter invokeTwo $n") action1(n) println("exit invokeTwo $n") return action2 }
如上所示,在invokeTwo设置为inline的时候,将action2标记为noinline则可以将action2当作返回值返回否则不可以
9、inline对应的crossinline
如果我们既要将lambda当成内联函数,又要将该lambda返回,则可以使用crossinline关键字
inline fun invokeTwo(n: Int, action1: (Int) -> Unit, crossinline action2: (Int) -> Unit): (Int) -> Unit { println("enter invokeTwo $n") action1(n) println("exit invokeTwo $n") return {input: Int -> action2(input)} // 既有return又要返回,则可以使用crossinline来做标记 } fun callInvokeTwo() { invokeTwo(1, {i -> if (i == 1) {return} report(i)}, {i -> if (i == 2) {return} // 这里使用了return所以需要用inline report(i)}) } callInvokeTwo()
标签:return,Int,kotlin,invokeWith,factor,println,lambda From: https://www.cnblogs.com/czwlinux/p/16879272.html