Lambda kotlin和#x27;s htmlx builder在引擎盖下工作到底是什么?

Lambda kotlin和#x27;s htmlx builder在引擎盖下工作到底是什么?,lambda,kotlin,jetbrains-ide,Lambda,Kotlin,Jetbrains Ide,这是一个片段,解释了htmlx builder的某些部分(来自文档): 因为head和body是html的成员函数。 但是DIV标签呢?我可以在任何地方声明div,而且我可以这样写: someEnclosingTag { (1..3).forEach { div {+"MyCustomDivFromEverywhere"} }} 封闭lambda如何知道可以在任何地方声明的“child”lambda(以及分别向整个html添加的“child”标记)? 如果我在什么地方错了,请纠正我 更新 根

这是一个片段,解释了htmlx builder的某些部分(来自文档):

因为head和body是html的成员函数。 但是DIV标签呢?我可以在任何地方声明div,而且我可以这样写:

someEnclosingTag { (1..3).forEach { div {+"MyCustomDivFromEverywhere"}  }}
封闭lambda如何知道可以在任何地方声明的“child”lambda(以及分别向整个html添加的“child”标记)?

如果我在什么地方错了,请纠正我

更新

根据答案,我以以下肮脏的伪代码结束,它显示了函数作用域(闭包的某些方面)和隐式接收器省略(希望它能以某种方式帮助某人):

fun main(args:Array){
童趣{
/*childFun lambda receiver实现parent1Fun lambda receiver,因此可以省略该接收器*/
家长1基金{
/*来自子系统的呼叫。(->单元接收器*/
一些有趣的事
}
/*与parent1Fun相同*/
家长2基金{
/*来自子系统的呼叫。(->单元接收器*/
一些有趣的事
}
}
}
childFun(lambda:Child.(->单位):Child=genericFun(Child(),lambda)
乐趣ParentInt1.parent1Fun(lambda:ParentInt1.)->Unit:ParentInt1=genericFun(Child(),lambda)
parent2Fun(lambda:ParentInt2.(->单位):ParentInt2=genericFun(Child(),lambda)
fun genericFun(实例:T,lambda:T.()->单位):T{
instance.lambda()
返回实例
}
接口ParentInt1
接口ParentInt2
类子项:ParentInt1、ParentInt2{
fun someIntrestingFun(){println(this)}
}

您可以在语言参考中找到更多关于构建此类DSL的技术,请参见:,该页面给出了一个HTML生成器示例(尽管kotlinx.HTML更为复杂)

封闭的lambda如何知道可以在任何地方声明的“子”lambda

这就是函数解析的工作原理:当您在内部lambda中嵌套了lambda(带接收器或不带接收器)时,您可以在外部lambda的接收器(*)上调用成员/扩展函数,下面是一个非常综合的示例:

with(arrayListOf<String>()) {
    with(hashMapOf<Int, String>()) {
        // You can call both functions of `ArrayList` and `HashMap`:
        add("foo")
        put(1, "bar")

        // Even in the nested lambdas with no receiver:
        baz.forEach { put(it, "it = $it") }
    }
}
with(arrayListOf()){
使用(hashMapOf()){
//您可以同时调用'ArrayList'和'HashMap'函数:
添加(“foo”)
put(1,“bar”)
//即使在没有接收器的嵌套lambda中:
forEach{put(it,“it=$it”)}
}
}


(*):在高级DSL中,可以使用限制作用域,以避免意外地从外部作用域调用接收器上的函数。

谢谢!!!我读了很多关于类型安全构建器的书,但是没有足够的关于函数解析机制的信息。你能提供一些能帮助我深入研究的参考资料吗。另外,如果我是对的,则nested lambdas中的接收方遗漏也引用了相同的机制。有一个正在进行的规范(目前还很原始,但它的内容仍然很精确)解释了一些函数解析逻辑:。除此之外,我不知道有什么好的渊博知识来源。不过,搜索有关构建Kotlin DSL的文章可能会帮助您提供示例。
someEnclosingTag { (1..3).forEach { div {+"MyCustomDivFromEverywhere"}  }}
fun main(args: Array<String>) {
    Child().childFun {
        /*childFun lambda receiver implements parent1Fun lambda receiver, so the receiver can be omitted*/
        parent1Fun {
            /*call from Child.() -> Unit receiver*/
            someIntrestingFun()
        }
        /*same as with parent1Fun*/
        parent2Fun {
            /*call from Child.() -> Unit receiver*/
            someIntrestingFun()
        }
    }
}

fun Child.childFun(lambda: Child.() -> Unit): Child = genericFun(Child(), lambda)

fun ParentInt1.parent1Fun(lambda: ParentInt1.() -> Unit): ParentInt1 = genericFun(Child(), lambda)

fun ParentInt2.parent2Fun(lambda: ParentInt2.() -> Unit): ParentInt2 = genericFun(Child(), lambda)

fun <T> genericFun(instance:T, lambda:T.() -> Unit): T {
    instance.lambda()
    return instance
}

interface ParentInt1
interface ParentInt2

class Child : ParentInt1, ParentInt2 {
    fun someIntrestingFun() { println(this) }
}
with(arrayListOf<String>()) {
    with(hashMapOf<Int, String>()) {
        // You can call both functions of `ArrayList` and `HashMap`:
        add("foo")
        put(1, "bar")

        // Even in the nested lambdas with no receiver:
        baz.forEach { put(it, "it = $it") }
    }
}