为什么 apply() 而不是函数调用

Why apply() instead of function invokation

下面的代码做同样的事情。函数 trtd 函数字面量和接收者对象 作为输入,以添加 tr 或table.

内的 td 标签
class TABLE : Tag("table") {
    fun tr(init: TR.() -> Unit) {
        children += TR().apply(init)
    }
}

class TR : Tag("tr") {
    fun td(init: TD.() -> Unit) {
        val td = TD()
        td.init()
        children += td
    }
}

我的问题是为什么我需要使用 .apply() 而不是:

class TABLE : Tag("table") {
    fun tr(init: TR.() -> Unit) {
        children += TR().init()
    }
}

我想这与编译器在 tr 对象中寻找 init() 有关。但这不应该在运行时决定吗?

正如我在评论中已经建议的那样,使用 .apply 您可以 调用 init+= 在一起,因为 apply returns 调用的目标。

如果您更喜欢使用init(),您可以使用

获得相同的结果
val tr = TR()
children += tr
tr.init()

chained 变体的关键方面是 applyfunction of the Kotlin's standard library is defined as an extension function of a generic typeT, accepting a *lambda with receiver 作为其唯一参数,如您所见 here:

inline fun <T> T.apply(block: T.() -> Unit): T

为了解释它的意思,你可以自己实现这个功能:

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

以下示例模仿您的代码,使用伪造的 MyClass 类型代替原始 TR:

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

class MyClass(val text: String) {
    fun foo() : Unit {
        println("foo $text")
    }
}

fun initializer(mc: MyClass) {
    println("initializer ${mc.text}")
    mc.foo()
}

fun run(init: MyClass.() -> Unit) {
    val result = MyClass("first").myApply(init)
    val x = MyClass("second")
    x.init()
}

fun main(args: Array<String>) {
    run(::initializer)
}

您可以玩这个例子,以便跟随从 runMyClass.foo 的流程,通过函数接受 init 作为 lambda 和接收器 参数:我希望这可以帮助您阐明对 tr.

的原始实现和替代实现的关键特征的理解