Incorrecto "esto" se usa en cierres nesteds

Intento mantener esto mínimo, pero avíseme si soy demasiado mínimo.

Supongamos que tiene una jerarquía de classs como esta, diseñada para generar HTML (inspirada en el tutorial de Kotlin, seguido de semi-pseudocódigo):

class Tag { protected val children = arrayListOf<Tag>() operator fun String.unaryPlus() = children.add(Text(this)) } class TagWithChildren : Tag() { fun head(init: Head.() -> Unit) = initializeTag(Head(), init) fun script(init: Script.() -> Unit) = initializeTag(Script(), init) fun <T : Tag> initializeTag(tag: T, init: T.() -> Unit): T { tag.init() children.add(tag) return tag } } class Head : TagWithChildren() class Script : Tag() class Text(val str: Text) : Tag() 

Observe que Head tiene methods de head y script , mientras que Script no.

Ahora puedes build una plantilla que se vea así:

 head { script { +"alert('hi');" } } 

¡Lo cual funciona genial! Sin embargo, si el bloque pasado a la script de script intenta llamar a methods que no están disponibles en la Script de Script , puede llamar al método en la cabeza en su lugar . Por ejemplo,

 head { script { script { +"alert('hi');" } } } 

no solo no es un error de compilation, en realidad es equivalente a

 head { script { } script { +"alert('hi');" } } 

que es muy confuso , desde la perspectiva de un autor de plantilla.

¿Hay alguna manera de evitar que las búsquedas de methods viajen por el ámbito de esa manera? Solo quiero que mire el scope más interno.


ACTUALIZACIÓN 24/11/2016: Kotlin 1.1-M03 ha introducido el control de scope, que creo que resuelve exactamente este problema. https://blog.jetbrains.com/kotlin/2016/11/kotlin-1-1-m03-is-here/

El comportamiento actual es intencional. El código en una lambda tiene acceso a los receptores de todos los ámbitos adjuntos. Es posible que una versión futura de Kotlin agregue un modificador que restringirá una lambda con receptor a los methods de llamada en ese receptor solamente y no en los ámbitos circundantes, pero en la versión actual no hay manera de cambiar ese comportamiento.

Como solución alternativa, puedo hacer que falle en el time de ejecución si cambio las classs para que se vean así:

 open class Tag { operator fun String.unaryPlus() // pulled up from TagWithChildren, call protected method fun head(init: Head.() -> Unit) = addChild(Head()) fun script(init: Script.() -> Unit) = addChild(Head()) // throws in Tag open protected fun addChild(t: Tag) = throw IllegalArgumentException() } class TagWithChildren : Tag() { // overridden to not throw in subclass protected override fun addChild(t: Tag) = children.add(t) } 

De esta forma, cada Tag tiene los methods de compilation (que resuelven el problema del scope), pero en realidad llamarlos puede provocar un error en el time de ejecución.

  • Anotar getter de la propiedad
  • Eclipse Aether no resuelve `MÁS RECIENTE` correctamente
  • Android JUnit testing bloques indefinidamente cuando observó Observable en AndroidSchedulers.mainThread ()
  • cómo configurar kotlin-logging logger
  • Multiplicación de Kotlin entre los errores de flotación que aceptan nulos y los que no admiten nulos incluso con verificación nula
  • Invocando Acción por reference en Kotlin
  • jvm comparando String con StringBuffer.reverse () siempre falla
  • Kotlin coroutine no espera a ser hecho
  • ¿Cómo puedo crear un encabezado de columna nested / dividido usando TornadoFx?
  • Kotlin - println usando una plantilla de cadena para stderr
  • Kotlin invoke getter / setter reflexivamente