当我们有扩展函数时,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。