深入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

  1. 匿名函数,使用表达式作为函数体。这种匿名函数无法正常调用。
  2. 传递一个匿名函数给 filter 作为参数,注意匿名函数的写法比 lambda 表达式要繁琐。如果匿名函数的函数体是表达式,那么匿名函数的返回值可以推断。因此这里的 Boolean 不是必须的。
  3. 用语句块作为匿名函数的函数体。

和 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

  1. substract 是一个函数类型。Int. 指定了一个 Int 类型作为接收者。后面的内容则是函数字面值,也就是 substract 函数的签名(参数、返回值)和函数体。函数体中调用了一个 lambda表达式,other 是入参,this 是接收者自身。
  2. 通过一个 Int 实例 123 来调用这个函数。这里 123 就变成了接收者。

函数的字面值除了使用 lambda 表达式以外(如上面),我们也可以使用匿名函数(如下面):

    val sum = fun Int.(other: Int): Int = this+other // 1
    println(123.sum(2)) // 2
  1. 使用匿名函数作为函数字面量,和 lambda 表达式相比,多了一个 fun 关键字,少了一个 -> 符号和大括号。这句也可以写成:

    val sum = fun Int.(other: Int): Int this+other  // 表达式换成语句块
    
  2. 调用方式一样。

带接收者的函数=不带接收者的函数

在 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)
  1. 这里定义了一个“带接收者的函数” myEquals,它定义了一个接收者 String,接收一个 Int 参数,返回 Boolean。
  2. 函数 test 的第一个参数也是一个函数,而且是不带接收者的函数,它定义了两个参数:一个 String 和一个 Int,同样返回 Boolean。
  3. 因此,它们刚好是一个”带接收者函数“及其”不带接收者的版本“的例子。因此调用 test 函数时,第一个参数可以用”带接收者版本“。
  4. 当然,也可以用”不带接收者版本“。

从上面的例子看出,带接收者函数传递的参数更少,因而书写更加简便。

以上是关于深入kotlin - 匿名函数闭包和接收者的主要内容,如果未能解决你的问题,请参考以下文章

带有不匹配参数的闭包调用:函数'_RegisterState.build.<匿名闭包>'接收者:闭包:(字符串)=> Null

Kotlin中匿名函数(又称为Lambda,或者闭包)和高阶函数的详解

kotlin的this关键字

Kotlin进阶系列-函数类型及函数字面值

Python学习---匿名函数和闭包的学习

Kotlin中匿名函数(又称为Lambda,或者闭包)的详解