Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin “错误”;这";在嵌套闭包中使用_Kotlin - Fatal编程技术网

Kotlin “错误”;这";在嵌套闭包中使用

Kotlin “错误”;这";在嵌套闭包中使用,kotlin,Kotlin,我正试图保持这一最低限度,但如果我太低,请告诉我 假设您有这样一个类层次结构,设计用于生成HTML(灵感来自Kotlin教程;下面是半伪代码): 太棒了!但是,如果传递给script的块试图调用script上不可用的方法,它可以调用Head上的方法。比如说, head { script { script { +"alert('hi');" } } } 它不仅不是编译错误,实际上相当于 head { script {

我正试图保持这一最低限度,但如果我太低,请告诉我

假设您有这样一个类层次结构,设计用于生成HTML(灵感来自Kotlin教程;下面是半伪代码):

太棒了!但是,如果传递给
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)
}