Scala和前向引用

时间:2012-08-29 19:15:45

标签: scala reference compilation

  

可能重复:
  Scala: forward references - why does this code compile?

object Omg {

  class A

  class B(val a: A)

  private val b = new B(a)

  private val a = new A

  def main(args: Array[String]) {
    println(b.a)
  }

}

以下代码打印“null”。在java中。由于前向引用无效,类似的构造无法编译。问题是 - 为什么它在Scala中编译得很好?这是设计,在SLS中描述还是仅仅是2.9.1中的错误?

4 个答案:

答案 0 :(得分:27)

这不是一个bug,而是学习Scala时的一个经典错误。初始化对象Omg时,首先将所有值设置为默认值(在本例中为null),然后运行构造函数(即对象主体)。

要使其正常工作,只需在您正在引用的声明前添加lazy关键字(在这种情况下为值a):

object Omg {

  class A

  class B(val a: A)

  private val b = new B(a)

  private lazy val a = new A

  def main(args: Array[String]) {
    println(b.a)
  }
}

然后将根据需要初始化值a

这种结构很快(值只对所有应用程序运行时初始化一次)和线程安全。

答案 1 :(得分:7)

我理解它的方式,这与Scala类的创建方式有关。在Java中,上面定义的类将内联初始化变量,并且由于a尚未定义,因此无法编译。但是,在Scala中,它在Java中更相当于它(在同一场景中也应该生成null):

class Omg {
  private B b = null;
  private A a = null;

  Omg(){ 
    b = new B(a);
    a = new A();
  }
}

或者,您可以声明b lazy,这将推迟设置值,直到调用它为止(此时将设置a)。

答案 2 :(得分:6)

如果这是一个问题,请在开发过程中使用-Xcheckinit进行编译并迭代,直到异常消失为止。

规范5.1按顺序执行的模板体语句; 4.0的开头,用于块中的前向引用。

Forward References - why does this code compile?

答案 3 :(得分:2)

正如@paradigmatic所说,这不是一个真正的错误。它是初始化顺序,遵循声明顺序。在这种情况下,a在声明/初始化b时为空。

将行private val b = new B(a)更改为private lazy val b = new B(a)将解决问题,因为使用lazy会延迟init。 b对它的第一次使用。

很可能在SLS中描述了这种行为。