这是一个片段,解释了htmlx构建器的某些部分(来自文档):
protected fun <T : Element> initTag(tag: T, init: T.() -> Unit): T {
tag.init()
children.add(tag)
return tag
}
主要观点是children.add(tag)
,因此我们可以声明:
html {
head {}
body {}
}
因为头部和身体是html的成员函数。 但是 DIV 标签怎么样?我可以在任何地方声明div,而且我可以这样写:
someEnclosingTag { (1..3).forEach { div {+"MyCustomDivFromEverywhere"} }}
封闭lambda如何知道&#34; child&#34; lambdas(以及分别为整个html添加&#39; child&#39;标签)可以在任何地方声明?
如果我在某处错了,请纠正我。
更新
基于回答,我结束了以下脏 - 虚拟代码,它显示了函数范围(闭包的某些方面)和隐式接收器遗漏(希望它能以某种方式帮助某人):
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) }
}
答案 0 :(得分:1)
您可以在语言参考中找到有关构建此类DSL的技术的更多信息,请参阅:Type-Safe Builders,该页面提供了一个示例HTML构建器(尽管kotlinx.html更复杂)。
封闭lambda如何知道可以在任何地方声明的“child”lambdas?
这是函数解析的工作原理:当你有嵌套的lambdas,带接收器或者没有接收器时,你可以在外部的接收器上调用成员/扩展函数(*),这是一个非常合成的例子:
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") }
}
}
(*):在高级DSL中,可以使用@DslMarker
限制范围,以避免从外部范围意外调用接收器上的函数。