【问题标题】:Scala and forward references [duplicate]Scala和前向引用[重复]
【发布时间】:2012-12-23 14:34:36
【问题描述】:

可能重复:
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”。在爪哇。由于无效的前向引用,类似的构造无法编译。问题是 - 为什么它在 Scala 中编译得很好?这是设计使然,在 SLS 中描述还是只是 2.9.1 中的错误?

【问题讨论】:

  • 让我烦恼的问题是它允许 val 更改其值。这让我很难过:-(
  • 这有点奇怪 - 可能会导致很多错误,我依赖于 Java 行为,这需要在使用之前初始化值。
  • @jdevelop 甚至 java 也无法捕获所有可能的前向引用。
  • @DanielC.Sobral 但这种情况很明显。
  • 我在包对象方面遇到了同样的问题。

标签: scala reference compilation


【解决方案1】:

这不是错误,而是学习 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 然后将按需初始化。

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

【讨论】:

  • 添加 lazy 如果你知道你正在以错误的顺序执行语句。但如果您认为它们的顺序正确,您可能不会想到添加“不必要的”lazy。 ://
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

    按照我的理解,这与 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();
      }
    }
    

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

    【讨论】:

      【解决方案4】:

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

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

      Forward References - why does this code compile?

      【讨论】:

        猜你喜欢
        • 2017-01-20
        • 2020-11-19
        • 2013-10-15
        • 2015-10-15
        • 2015-10-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多