下面的结果都在Intellij IDEA Scala工作表中,但标准Scala REPL似乎一致,因此这可能是由于工作表的包装。
scala puzzlers网站上有一个谜题。
object XY {
object X {
val value: Int = Y.value + 1
}
object Y {
val value: Int = X.value + 1
}
}
println(if (math.random > 0.5) XY.X.value else XY.Y.value)
提到的正确答案是2(对于scala 2.10.0?)。然而,在Intellij工作表(scala 2.11.7)中,它会发出stackoverflowError。
另外,正如规范
中提到的对象定义定义了一个符合模板tt的对象(或:module)。它大致相当于以下惰性值
的定义
确实下面也会给出stackoverflowError。
lazy val x: Int = y + 1
lazy val y: Int = x + 1
这里有一些其他的观察。
案例1
object XXX {
val x: Int = y + 1
lazy val y: Int = x + 1
}
s"XXX x=${XXX.x} y=${XXX.y}"
// XXX x=2 y=1
案例2
val x: Int = y + 1
s"plain x=$x"
lazy val y: Int = x + 1
s"plain y=$y"
// stackoverflowError
情况3
object XXX {
val x: Int = y + 1
lazy val y: Int = x + 1
}
s"XXX x=${XXX.x} y=${XXX.y}"
val x: Int = y + 1
s"plain x=$x"
lazy val y: Int = x + 1
s"plain y=$y"
// XXX x=2 y=1
// NO output any longer for subsequent scripts
是已知的Intellij scala插件错误吗?
在Scala 2.11.8上我没有得到错误,我猜这与你的设置中的其他东西有关。你给出的链接很好地解释了为什么这样做——它基本上归结为JVM初始化魔法,具体来说:
VM注意到对象X已经初始化运行并返回X.value的当前值,该值为零(Int字段的默认值),因此在运行时不会发生堆栈溢出。
然而,没有理由让这种魔力也适用于
lazy val x: Int = y + 1
lazy val y: Int = x + 1
应该是堆栈溢出
<标题>案例1这里没有什么奇怪的-这只是初始化之前字段的默认值为0的通常情况。在x
的初始化期间(首先发生),y
的初始化被触发,它使用x
的当前值(默认为0
,因为x
尚未初始化)并计算y = 0 + 1 = 1
。然后,返回初始化x
,计算x = 1 + 1 = 2
。
error: forward reference extends over definition of value x
val x: Int = y + 1
^
我想说Intellij IDEA Scala工作表没有正确处理这个问题。
<标题>情况3 关于这件事我什么也不能说。在前面的案例中,我已经介绍了预期的Scala输出——这完全取决于代码是如何包装的(在对象/类或方法/函数中)。再一次,Intellij IDEA Scala工作表似乎不工作。 标题>标题>标题>