¿Cómo funciona el generador htmlx de kotlin exactamente debajo del capó?

Este es un fragment que explica alguna parte del constructor htmlx (de la documentation):

protected fun <T : Element> initTag(tag: T, init: T.() -> Unit): T { tag.init() children.add(tag) return tag } 

El punto principal es children.add(tag) , entonces podemos declarar:

 html { head {} body {} } 

porque la cabeza y el cuerpo son funciones miembro de html. Pero, ¿qué pasa con la label DIV ? Puedo declarar div en todas partes, además puedo escribir algo como esto:

 someEnclosingTag { (1..3).forEach { div {+"MyCustomDivFromEverywhere"} }} 

¿De qué manera el encierro de lambda sabe acerca de las lambdas "hijo" (y respectivamente, la label "hijo" de add en html integer) que pueden declararse en todas partes?

Por favor, corrígeme, si estoy equivocado en alguna parte.

ACTUALIZAR

basado en la respuesta, terminé con el siguiente código sucio, que muestra los ámbitos funcionales (algunos aspectos del cierre) y la omisión implícita del receptor (espero que de alguna manera pueda ayudar a alguien):

 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) } } 

Puede encontrar más información sobre las técnicas para comstackr tales DSL en la reference del lenguaje, consulte: Type-Safe Builders , y esa página proporciona un ejemplo de constructor de HTML (aunque kotlinx.html es más complicado).

¿Cómo sabe encierra a lambda sobre lambdas "infantiles" que se pueden declarar en todas partes?

Así es como funciona la resolución de la function: cuando ha nested lambdas, con receptor o no, en las internas puede llamar funciones de miembro / extensión en los receptores de las externas (*) , aquí hay un ejemplo muy sintético:

 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") } } } 

(*): En las DSL avanzadas, el scope puede restringirse con @DslMarker , para evitar llamar accidentalmente a una function de un receptor desde el scope externo.

  • Tipo Lambda con número variable de args en Kotlin?
  • Tratando de entender el ejemplo de Kotlin
  • Tienda lambda en una variable en kotlin
  • Tipo de function con receptor en Scala
  • Kotlin Cualquiera con lambdas
  • Anulación de múltiples methods de interfaz en expresiones Kotlin lambda
  • Funciones de Lambda con comodines en Kotlin
  • ¿Por qué la variable no se puede inicializar correctamente en la function en línea como en Java?
  • La expresión lambda no se usa
  • Kotlin: uso ilegal de devolución de parameters en línea
  • ¿Cómo usar la expresión Lamba para hacer que las llamadas al método Java sean less detalladas en Kotlin?