在下面的程序中,一个对象被报告为 null,即使它已明确初始化。
class MyClass()
class MyOtherClass(c: MyClass)
object Foo {
val myClass = new MyClass()
object otherClass extends MyOtherClass(myClass)
val otherClasses = Seq(otherClass)
}
object Main {
def main(args: Array[String]): Unit = {
println(Foo.otherClass)
println(Foo.otherClasses)
}
}
打印:
Foo$otherClass$@5410511c
List(null)
现在我通过制作
otherClasses
lazy
解决了这个问题。也可以通过将参数从 MyOtherClass
更改为 null
来解决,但这对我来说不是一个选择。
我总是假设 scala 中对象和类的初始化顺序是从上到下的。显然我的假设是错误的。看起来 vals 首先被初始化。这是边缘情况还是错误?我认为 scala 2 和 3(在 scastie 中都是 3.3.3. 和 3.4.2)中的行为是相同的。
object
会延迟初始化多年。在 Scala 2.13 规范中,我们读到:
对象定义定义了符合以下条件的单个对象(或:模块) 到模板 tt。大致相当于以下 惰性值的定义:
lazy val mm = new scsc with mt1mt1 with …… with mtnmtn { this: m.typem.type => statsstats }
注意对象定义定义的值是实例化的 懒洋洋。新的 mm$cls 构造函数的计算不是在 对象定义,但在第一次 mm 时进行评估 在程序执行期间取消引用(可能永远不会在 全部)。在评估期间再次尝试取消引用 mm 构造函数将导致无限循环或运行时错误。其他 正在评估构造函数时尝试取消引用 mm 的线程会阻塞,直到评估完成。
Scala 3 没有改变这种行为(尽管 Scala 3 还没有发布它的规范,所以我无法根据规范设置它,但当它发布时我确信这将是预期的行为)。
如果您知道
object otherClass
是惰性值,那么 null
就非常有意义。初始化的顺序是从上到下,但只初始化急切的值,并且 lazy val
(和 object
)是当你必须格外小心并且不要在构造函数中评估它们时。