我正在努力理解以下代码(源代码(。
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
这里发生了什么?
有人能简单地解释一下这里发生了什么吗?
首先,让我们让这个例子简单一点,看看问题是什么。
我们可以这样构建html
函数:
fun html(init: (HTML) -> Unit): HTML {
val html = HTML()
init(html)
return html
}
这将更容易理解(一开始(,因为我们只是将一个常见的单参数lambda传递给html
函数。
但现在的呼叫站点并不像建设者:
html { it: HTML -> // just for clarity
it.body() // not very nice
}
如果我们可以在没有it
的情况下在html
内部调用body()
,那不是很好吗?这是可能的!我们只需要一个带接收器的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()
}
由于this
可以省略,我们到达这里:
html {
body()
}
因此,最终,带有接收器的lambda使代码更加简洁,并允许我们使用良好的生成器语法。
以下是逐步解释:
1.创建函数,接收器类型lambda
fun html(init: HTML.() -> Unit): HTML {
函数html接受类型为CCD_ 13的参数CCD_。: 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
的实例调用方法(函数(,即使它是lambda,因为它是一个接收器。
PS:对于简单的langauge,您可以将html.init((视为init(html(,但html不是一个参数,而是在lambda中可用的this
这就是为什么您能够在该lambda上调用body()
,因为隐式地调用this.body()
,而this
来自html.init()
的html对象。