Kotlin(lambda函数)
lambda
lambda表达式
根据图片可以比较清晰的了解lambda的语法,他通过->
将参数和函数体分开,参数不用带小括号,整体都用一个中括号括起来,箭头右边写函数体,函数体可以写多行,最后一行做为表达式的值传递回去。
为了让你加深理解。
- 实例1:以上内容,肯定了lambda函数表达式,他本身就是一个函数,可以直接使用。像一个正常函数一样。
1
2
3
4fun main(args: Array<String>) {
//{x:Int,y:Int -> x+y}本身就是一个函数
println({x:Int,y:Int -> x+y}(1,2))
}
但是这样子意义不大,就像是刻意为之 - 实例2:kotlin作为函数式编程语言。他可以直接把函数传递给一个变量存储。而且该变量可以被其他类,函数所接受。这也是kotlin的一大特点之一。这个被保存到函数同样可以像正常函数一样使用。
1
2
3
4fun main(args: Array<String>) {
var sum = {x:Int,y:Int -> x+y}
println(sum(1,3))
}
注意点
通常使用lambda函数有一些特点
0. 如果传递进去的参数类型是可知的,可以直接省略掉该参数的类型声明,而直接交给编译器,自动推导
- 如果只有一个参数,那么这个参数可以直接省略,用
it
来代替 - 如果函数被作为一个方法的参数,而且是最后一个参数,那么这个函数可以被写在小括号后面,单独列出来。
- 如果一个类或者一个方法接受一个函数作为变量,而且只接受一个变量,那么可以直接省略小括号,直接放lambda函数上去(当然,不用lambda也行,用其他的函数体)
在作用域中访问变量
在kotlin中,他的lambda函数不仅可以获取到局部变量,还可以修改这个局部变量。我们称这些变量被lambda捕捉
1 | fun main(args: Array<String>) { |
展现结果为:
实现细节:
- 首先,在java中,他只允许你捕捉final变量,也就是kotlin中的val变量,他们不可被修改,只能读取。
- 当你捕捉val变量时,系统会将这个值和lambda代码一起存储。
- 当你要捕获var变量,并进行更改时,他会采用两种方法之一,要么声明一个单元素的数组,其中存放可变值。或者创建一个包装类的实例,把这个var变量作为该实例的一个属性,而且可以修改。
在上述图片中,第一段代码就是对第二段代码的解释。
当kotlin中捕获一个var变量时,他会创建一个val的包装类,然后存储该包装类的实例,而这个包装类因为时val的,所以很好获取。
注意事项
如果 lambda 被用作事件处理器或者用在其他异步执行的情况,对局部变量的修改只会在 lambda 执行的时候发生。
意思是说,如果你这个lambda函数作为异步处理的,所以你修改的这个局部变量最好能够通过其他类,或者全局保存。不然他将无法修改成功。
成员引用
他的使用场景是,当你需要把一个已经定义好的函数抠下来,作为一个参数传递给其他需要使用这个函数参数的地方。
这种表达式称为成员引用,用双冒号把你要引用的成员(一个属性或者一个方法)和类名称隔开。
如果是顶层函数,可以直接用::方法名获取
构造方法
可以用构造方法引用 存储或者延期执行创建类实例的动作 构造方法引用的形式,是在双冒号后指定类名称:
不难理解,所以直接跳过
详解成员引用
成员引用和调用该函数的 lambda 具有一样的类型,所以可以互换使用:这句话请深刻记忆,他很重要。
顶层函数
直接从顶层方法中获取的方法,他不需要再接受额外的参数,可以直接通过run方法去执行他的函数体,如下:
1 | fun salute() = println("Salute !") |
这两个语句的执行结果一致,都会输出Salute !
。
如果这个函数有参数的话,而run方法默认是不带参数的。
源码如下:
1 | .internal.InlineOnly |
因此可以通过其他方法,比如用一个参数去接受函数体,然后像正常函数一样执行。
非顶层函数
如果是某个类中的函数,那么他会有一个限制。
那就是如果你要使用这个函数的话,他一定需要传入一个他该类的实例进去,不然就会语法报错。
例如:
1 |
|
他要求必须传入一个实例进去。
但是在kotlin1.1后版本更新,允许进行绑定引用。
也就是直接引用来自实例的方法。
如下:
1 | import kotlin.reflect.KFunction1 |
以上