Kotlin “错误”;这";在嵌套闭包中使用
我正试图保持这一最低限度,但如果我太低,请告诉我 假设您有这样一个类层次结构,设计用于生成HTML(灵感来自Kotlin教程;下面是半伪代码): 太棒了!但是,如果传递给Kotlin “错误”;这";在嵌套闭包中使用,kotlin,Kotlin,我正试图保持这一最低限度,但如果我太低,请告诉我 假设您有这样一个类层次结构,设计用于生成HTML(灵感来自Kotlin教程;下面是半伪代码): 太棒了!但是,如果传递给script的块试图调用script上不可用的方法,它可以调用Head上的方法。比如说, head { script { script { +"alert('hi');" } } } 它不仅不是编译错误,实际上相当于 head { script {
script
的块试图调用script
上不可用的方法,它可以调用Head上的方法。比如说,
head {
script {
script {
+"alert('hi');"
}
}
}
它不仅不是编译错误,实际上相当于
head {
script {
}
script {
+"alert('hi');"
}
}
从模板作者的角度来看,这非常令人困惑
有没有任何方法可以防止方法查找像这样向上移动?我只想让它看最里面的范围
更新日期:2016年11月24日:
Kotlin 1.1-M03引入了范围控制,我相信这正好解决了这个问题 作为一种解决方法,如果我将类更改为如下所示,我可以让它在运行时失败:
head {
script {
+"alert('hi');"
}
}
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)
}
这样,每个标记都有生成器方法(解决范围问题),但实际调用它们可能会导致运行时失败。当前行为是故意的。lambda中的代码可以访问所有封闭作用域的接收器。Kotlin的未来版本可能会添加一个修饰符,该修饰符将限制lambda with receiver仅在该接收器上调用方法,而不是封闭作用域,但在当前版本中,无法更改该行为。对不起,您的第一个代码段中的
Head
是什么?请您发布真正的声明,因为在谈论构建器和作用域时,小细节很重要。@voddan done…很抱歉,当我真正使用Ruby子类化语法时,我认为我是泛型的。您确定您的代码中有这样的内容吗?坦率地说,我很惊讶它能起作用fun head(init:head.(->Unit)=children.add(head())
-这里不使用init
,我省略了一些不太相关的细节。我只是想看看我是否可以选择Kotlin编译器所做的范围遍历。至于现在,您没有在任何地方调用init
方法,我无法想象没有它它它会工作。也许你的意思是fun-head(init:head.(->Unit)=children.add(head().init())
那么,有没有办法创建类型安全的构建器呢?解决方法?谢谢@yole。这是有道理的——这是人们期望闭包工作的方式,在非构建器的情况下,通常是人们想要的。见鬼,即使我希望它用于变量访问,但不希望用于方法访问,这当然有点武断。感谢您的确认。顺便说一句,在我偶然发现的这篇旧文章中,在“最后一个问题”开头的一段中,基本上记录了这种行为。另一种变通方法是对特定对象调用head
和script
builder方法,即this.script
/this.head
(如果接收方未作为参数传递,则使用apply
)或tag.script
/tag.head
(如果接收方作为参数传递,则使用let
)。但是仍然很麻烦。您可以弃用Tag.addChild
方法,以便IDE将其划掉并从编译中删除
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)
}