Scala 和前向引用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12184997/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 04:29:07  来源:igfitidea点击:

Scala and forward references

scalareferencecompilation

提问by jdevelop

Possible Duplicate:
Scala: forward references - why does this code compile?

可能的重复:
Scala:前向引用 - 为什么这段代码会编译?

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)
  }

}

the following code prints "null". In java. similar construction doesn't compile because of invalid forward reference. The question is - why does it compile well in Scala? Is that by design, described in SLS or simply bug in 2.9.1?

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

回答by paradigmatic

It's not a bug, but a classic error when learning Scala. When the object Omgis initialized, all values are first set to the default value (nullin this case) and then the constructor (i.e. the object body) runs.

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

To make it work, just add the lazykeyword in front of the declaration you are forward referencing (value ain this case):

要使其工作,只需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)
  }
}

Value awill then be initialized on demand.

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

This construction is fast (the values are only initialized once for all application runtime) and thread-safe.

这种构造速度很快(所有应用程序运行时的值只初始化一次)并且是线程安全的。

回答by jcern

The way that I understand it, this has to do with how the Scala classes are created. In Java, the class defined above would be initializing the variables inline, and since ahad not been defined yet, it could not be compiled. However, in Scala it is more the equivalent of this in Java (which should also produce null in the same scenario):

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

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

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

Alternately, you could make your declaration of blazy, which would defer setting the value until it is called (at which time a will have been set).

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

回答by som-snytt

If this is a concern, compile with -Xcheckinitduring development and iterate until the exceptions go away.

如果这是一个问题,请-Xcheckinit在开发期间编译并迭代,直到异常消失。

Spec 5.1 for template body statements executed in order; beginning of 4.0 for forward references in blocks.

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

Forward References - why does this code compile?

前向引用 - 为什么这段代码会编译?

回答by pedrofurla

As @paradigmatic states, it's not really a bug. It's the initialization order, which follows the declaration order. It this case, ais null when bis declared/init-ed.

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

Changing the line private val b = new B(a)to private lazy val b = new B(a)will fix issue, since using lazy will delay the init. of b to it's first usage.

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

It's very likely that this behavior is described in the SLS.

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