我正在尝试理解以下代码(来自https://kotlinlang.org/docs/reference/lambdas.html)
class HTML {
fun body() { ... }
}
fun html(init: HTML.() -> Unit): HTML {
val html = HTML() // create the receiver object
html.init() // pass the receiver object to the lambda
return html
}
html { // lambda with receiver begins here
body() // calling a method on the receiver object
}
我真正无法掌握的是线
html.init() // pass the receiver object to the lambda
这里发生了什么?
有人可以用简单的词解释这里发生了什么吗?
这里是分步说明:
1。创建函数,接收器类型为lambda。
fun html(init: HTML.() -> Unit): HTML {
此处的html函数接受类型为init
的参数HTML.() -> Unit
,即表示它是HTML的接收者,只能在真实的HTML对象的帮助下调用。 : HTML
表示该函数显然返回HTML对象。
2。调用html的init
html.init()
这里的init()函数被实际的HTML对象称为HTML的接收器。
可以说的很正式,这就是接收者的意思:
因此,如果您记得定义为fun A.myFun(...): ReturnType {}
的扩展功能,在这种情况下,您会得到一个变量this
,该变量充当类型A的实例,被调用。
类似地,接收器lambda在其中提供了一个this
变量,
在特定示例中:
class A {
fun thisCanBeCalledByAInstance() {
println("I've got called")
}
}
fun main() {
val receiver: A.() -> Unit = { // this: A
thisCanBeCalledByAInstance() // prints: I've got called
// or traditional way this.thisCanBeCalledByAInstance()
}
val a: A = A()
a.receiver()
}
在这里,您可以从A
的实例中调用method(function),即使它是lambda也因为它是接收者。
PS:对于简单的语言,您可以将html.init()视为init(html),但是html不是参数,而是可以作为this
在lambda中使用
这就是为什么您能够在该lambda上调用body()
的原因,因为您隐式地在调用this.body()
,并且this
来自html.init()
的html对象。
首先,让我们简化此示例,然后看问题出在哪里。我们可以像这样构建html
函数:
fun html(init: (HTML) -> Unit): HTML {
val html = HTML()
init(html)
return html
}
但是现在呼叫站点不是像这样的构建器:
html { it: HTML ->
it.body() // not very nice
}
但是(首先)这会更容易理解。我们只是将通常的一参数lambda传递给html
函数。
如果我们可以在没有body()
的情况下调用html
内的it
会很好吗?有可能!我们需要的是带有接收器的lambda。
fun html(init: HTML.() -> Unit): HTML { // <-- only this changed
val html = HTML()
init(html)
return html
}
[像以前一样,如何将html
作为参数传递给init
?当然,我们也可以像这样调用它:html.init()
如示例所示。 HTML
的实例在lambda块内变为this
。
现在,我们可以这样做:
html {
this.body()
}
由于可以省略,因此我们到达这里:
html {
body()
}
因此,最终带有接收器的lambda使代码更简洁,并允许我们使用不错的构建器语法。