在scala Intellij工作表中初始化两个相互依赖的val?

时间:2016-09-03 04:15:34

标签: scala intellij-idea

下面的结果是Intellij IDEA Scala Worksheet内的ALL,但标准的scala REPL似乎是一致的,因此这可能是由于工作表的包装

scala益智游戏网站上有一个谜题here

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。

另外,如spec

中所述
  

对象定义定义符合模板tt的单个对象(或:模块)。它大致相当于以下懒惰值的定义

下面也会给出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插件错误吗?

1 个答案:

答案 0 :(得分:1)

在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,因为{{1}尚未初始化)并计算x。然后,我们返回初始化y = 0 + 1 = 1,并计算x

案例2

这有点难看,因为这段代码需要在一些东西里面编译(一个对象,一个类,一个函数,一个方法,SOMETHING!)。在类或对象内部,上面的推理适用(这是Scala REPL中发生的事情,因为它基本上只是在对象内部运行裸代码)。

另一方面,如果你把它放在一个函数或方法中,它根本就不应该编译,因为你有一个前向引用。它应该失败,例如:

x = 1 + 1 = 2

我说Intellij IDEA Scala工作表没有正确处理。

案例3

我无法对此发表任何言论。在之前的案例中,我已经覆盖了预期的Scala输出 - 这完全取决于代码的包装方式(在对象/类或方法/函数中)。同样,Intellij IDEA Scala工作表似乎无法正常工作。