在嵌套的闭包中使用了错误的"this"

Max*_*Max 6 kotlin

我试图保持这个最小化,但如果我太小,请告诉我.

假设你有一个像这样的类层次结构,用于生成HTML(受Kotlin教程启发;后面是半伪代码):

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()
Run Code Online (Sandbox Code Playgroud)

请注意,Headhas headscript方法Script却没有.

现在您可以构建一个如下所示的模板:

head {
    script {
        +"alert('hi');"
    }
}
Run Code Online (Sandbox Code Playgroud)

哪个效果很好!但是,如果传递的块script尝试调用不可用的方法Script,则可以在Head上调用该方法.例如,

head {
    script {
        script {
            +"alert('hi');"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

不仅不是编译错误,它实际上相当于

head {
    script {
    }
    script {
        +"alert('hi');"
    }
}
Run Code Online (Sandbox Code Playgroud)

从模板作者的角度来看,这是非常混乱的.

有没有办法阻止方法查找这样的范围向上移动?我希望它看起来在最里面的范围.


更新2016年11月24日:Kotlin 1.1-M03引入了范围控制,我相信这正是解决了这个问题.https://blog.jetbrains.com/kotlin/2016/11/kotlin-1-1-m03-is-here/

Max*_*Max 2

作为一种解决方法,如果我将类更改为如下所示,我可能会在运行时失败:

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)
}
Run Code Online (Sandbox Code Playgroud)

这样,每个标签都有构建器方法(解决范围问题),但实际调用它们可能会导致运行时失败。

  • 您可以“弃用”“Tag.addChild”方法,以便 IDE 会划掉它并从编译中删除 (2认同)