深入kotlin - 匿名函数闭包和接收者
Posted 颐和园
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入kotlin - 匿名函数闭包和接收者相关的知识,希望对你有一定的参考价值。
匿名函数
匿名函数没有名字,它很大程度上和 lambda 表达式类似,它的函数体既可以是语句块,又可以是表达式。同时,匿名函数的参数类型可以推断而不用指定,这点跟普通的函数不同。此外,匿名函数只能定义在函数体内。
fun main(args:Array<String>)
fun(x:Int y:Int) = x+y // 1
val arr = arrayOf("hello","world","!")
arr.filter(fun(item): Boolean = item.length > 3) // 2
.forEach(fun(item) println(item)) // 3
- 匿名函数,使用表达式作为函数体。这种匿名函数无法正常调用。
- 传递一个匿名函数给 filter 作为参数,注意匿名函数的写法比 lambda 表达式要繁琐。如果匿名函数的函数体是表达式,那么匿名函数的返回值可以推断。因此这里的 Boolean 不是必须的。
- 用语句块作为匿名函数的函数体。
和 lambda 表达式不同,匿名函数中如果不使用全限定的 return 的话,返回的是匿名函数本身,而非外部函数。
在 kotlin 中,由于 lambda 的写法更简单,所以一般都会用 lambda 表达式代替匿名函数。可以简单地将二者视作等价物,我们可以用匿名函数`一词来指代 lambda 表达式。
闭包
lambda 表达式和匿名函数可以访问和修改其外层变量的。这些变量和lambda/匿名函数就构成了一个闭包。
带接收者的函数字面值
kotlin 在定义一个函数时,可以指定这个函数归属于哪个类(接收者)。在函数内部,你可以调用接收者的实例所拥有的方法,这有点类似于扩展函数。
fun main(args: Array<String>)
val substract: Int.(other:Int)->Int = other->this-other // 1
println(123.substract(3)) // 2
- substract 是一个函数类型。
Int.
指定了一个 Int 类型作为接收者。后面的内容则是函数字面值,也就是 substract 函数的签名(参数、返回值)和函数体。函数体中调用了一个 lambda表达式,other 是入参,this 是接收者自身。 - 通过一个 Int 实例 123 来调用这个函数。这里 123 就变成了接收者。
函数的字面值除了使用 lambda 表达式以外(如上面),我们也可以使用匿名函数(如下面):
val sum = fun Int.(other: Int): Int = this+other // 1
println(123.sum(2)) // 2
-
使用匿名函数作为函数字面量,和 lambda 表达式相比,多了一个 fun 关键字,少了一个 -> 符号和大括号。这句也可以写成:
val sum = fun Int.(other: Int): Int this+other // 表达式换成语句块
-
调用方式一样。
带接收者的函数=不带接收者的函数
在 kotlin 的函数中,带接收者的函数和不带接收者的函数中某种情况下是等价的,二者可以互相替换,比如:
String.(Int) -> Boolean
这是一个带接收者(String)的匿名函数(lambda),它定义了一个带 Int 参数和 Boolean 返回值的函数(lambda)。它实际上可以转换为:
(String, Int) -> Boolean
即将接收者作为第一个参数。我们可以把后者看作是前者的等价物,反之亦可。看如下例子:
val myEquals:String.(Int)->Boolean = param->toIntOrNull() == param // 1
println("456".myEquals(456)) // true
fun test(op:(String, Int)->Boolean, a:String, b:Int, c:Boolean)=println(op(a,b)==c) // 2
test(myEquals,"200",200,true) // 3
val equals:(String, Int)->Boolean = string, int -> string.toIntOrNull() == int // 4
test(equals, "200",200, true)
- 这里定义了一个“带接收者的函数” myEquals,它定义了一个接收者 String,接收一个 Int 参数,返回 Boolean。
- 函数 test 的第一个参数也是一个函数,而且是不带接收者的函数,它定义了两个参数:一个 String 和一个 Int,同样返回 Boolean。
- 因此,它们刚好是一个”带接收者函数“及其”不带接收者的版本“的例子。因此调用 test 函数时,第一个参数可以用”带接收者版本“。
- 当然,也可以用”不带接收者版本“。
从上面的例子看出,带接收者函数传递的参数更少,因而书写更加简便。
以上是关于深入kotlin - 匿名函数闭包和接收者的主要内容,如果未能解决你的问题,请参考以下文章
带有不匹配参数的闭包调用:函数'_RegisterState.build.<匿名闭包>'接收者:闭包:(字符串)=> Null