Kotlin接收器功能用于DSL所需的解释

问题描述 投票:1回答:2

我正在尝试理解以下代码(来自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

这里发生了什么?

有人可以用简单的词解释这里发生了什么吗?

kotlin dsl
2个回答
0
投票

这里是分步说明:

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对象。


0
投票

首先,让我们简化此示例,然后看问题出在哪里。我们可以像这样构建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使代码更简洁,并允许我们使用不错的构建器语法。

© www.soinside.com 2019 - 2024. All rights reserved.