奇怪的行为

时间:2012-02-08 20:36:16

标签: scala

case class Test(kind: Int) {
  val ifX = if (isX) "is X" else "not X"
  val isX = kind == 1
}

val test = Test(1)
println("ifX=%s, isX=%b".format(test.ifX, test.isX))

为什么要打印此代码: ifX = not X,isX = true

何时在“ifX”之前移动“val ifX”就可以了(打印ifX =是X)

编辑:我知道如何解决这个问题。我无法理解为什么编译器在这种情况下不会发出警告或错误。

4 个答案:

答案 0 :(得分:7)

您假设订单在scala中无关紧要。确实如此。因为isX是一个变量值,虽然它是在ifX运行时定义的,但它的值仍然未初始化,因此它是其类型的默认值(布尔值,所以为false)。

如果将isX重新定义为函数(def isX = ...),它将起作用。

这大致相当于以下Java:

class Test {
    String ifX;
    bool isX; // Defaults to false, its a primitive after all
    public Test(Int kind) {
        ifX = isX ? "is X" : "not X";
        isX = kind == 1;
    }
}

答案 1 :(得分:7)

正如Chris Shain所指出的,isX尚未定义。我只是想补充一点,它不是变量,而是,这意味着你实际上可以让它变得懒惰。只有在需要时才会实例化一个惰性值。理论上,ifXisX都可能变得懒惰。尝试这样的事情:

case class Test(kind: Int) {
   val ifX = if (isX) "is X" else "not X"
   lazy val isX = kind == 1
 }

那应该给出所需的输出。

答案 2 :(得分:7)

OMG,我想知道有多少次我们会经历这个......

在所有情况下都不可能以比指数时间更好的方式静态检测错误使用的前向引用。或者,如果是,那就足够复杂,没有人做过。

这个特殊情况很简单 - 没有继承,没有扩展特征,没有早期初始化器,没有调用方法,没有闭包,没有函数,没有任何东西。它很简单,以后可能会添加警告。

您可以在运行时捕获它,Scala为此提供-Xcheckinit标志。

顺便说一下,你可以在Java中得到完全相同的问题,尽管它会在这个特殊情况下警告你。

答案 3 :(得分:1)

嗯,当第一次运行类时,isX是未定义的。 你能切换两条线吗?