Lambda with Receiver 的目的是什么?



当我们有扩展函数时,Lambda在Kotlin中使用Receiver的目的是什么?

下面的两个函数做同样的事情,但第一个更可读且简短:

fun main(args: Array<String>) {
println("123".represents(123))
println(123.represents("123"))
}
fun String.represents(another: Int) = toIntOrNull() == another
val represents: Int.(String) -> Boolean = {this == it.toIntOrNull()}

带有接收器的Lambdas基本上与扩展函数完全相同,它们只是能够存储在属性中,并传递给函数。这个问题本质上与"当我们有函数时,lambdas的目的是什么?"相同。答案也是一样的——它允许您在代码中的任何位置快速创建匿名扩展函数。

这方面有很多好的用例(特别是DSL),但我在这里举一个简单的例子。

例如,假设你有一个这样的函数:

fun buildString(actions: StringBuilder.() -> Unit): String {
val builder = StringBuilder()
builder.actions()
return builder.toString()
}

调用此函数如下所示:

val str = buildString {
append("Hello")
append(" ")
append("world")
}

启用该语言功能有几个有趣的地方:

  • 在传递给buildString的lambda内部,您处于一个新的范围中,因此有新的方法和属性可供使用。在这种特定情况下,您可以在StringBuilder类型上使用方法,而不必在任何实例上调用它们
  • 这些函数调用的实际StringBuilder实例不是由您管理的,而是由函数的内部实现来创建一个实例并在其上调用扩展函数
  • 因此,这个函数也可以做更多的事情,而不仅仅是在一个StringBuilder上调用一次传递给它的lambda——它可以在各种StringBuilder实例上多次调用它,存储它以备将来使用,等等

相似性

从某种意义上说,扩展函数是具有接收器的函数。当您使用带有接收器的lambdas时,您正在利用Kotlin的扩展函数特性。

lambda是定义类似于正则函数的行为的一种方法。

带有接收器的lambda是定义类似于扩展函数的行为的一种方式。

要理解带有接收器的lambda的用途,请考虑以下创建并返回Button的示例函数。

fun createButton(): Button {
val button = Button()
button.text = "Some text"
button.height = 40
button.width = 60
button.setOnClickListener(listener)
button.background = drawable
return button
}

如上所述,您在button对象上调用了许多不同的方法,在每次调用中都重复名称button。这只是一个小例子。如果这个表情更长或重复多次,会很不方便,看起来也不好看。


用途

为了使其更加简洁、美观和可读,我们使用了带有receriver的lambda,并使用了扩展函数apply()。并重构上面的代码如下:

fun createButton() = Button().apply {
text = "Some text"
height = 40
width = 60
setOnClickListener(listener)
background = drawable
}

现在代码看起来更好看了。Button()是接收器对象,你可以调用方法并设置它的属性。

这在创建实例并立即初始化某些属性时非常有用。在Java中,这是使用Builder模式完成的。在Kotlin中,您可以在任何对象上使用apply(),即使它不支持Builder模式。

apply()函数在Kotlin标准库中定义如下(简化):

fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}

你可以用类似的方式用接收器定义你自己的Lambda。

最新更新