覆盖'val'时出现意外结果

Kev*_*ith 6 overriding scala

在Scala 2.10.4中,给出以下类:

scala> class Foo { 
     |   val x = true
     |   val f = if (x) 100 else 200
     | }
defined class Foo
Run Code Online (Sandbox Code Playgroud)

以下两个例子对我有意义:

scala> new Foo {}.f
 res0: Int = 100

scala> new Foo { override val x = false}.f
res1: Int = 200
Run Code Online (Sandbox Code Playgroud)

但是,为什么这个电话不会回来100

scala> new Foo { override val x = true }.f
res2: Int = 200
Run Code Online (Sandbox Code Playgroud)

Mic*_*jac 11

因为val不会多次初始化,x实际上null(或false默认情况下Boolean)初始化期间Foo,然后Foo在您的示例中扩展的匿名类中初始化.

我们可以通过以下方式更轻松地测试它AnyRef:

class Foo { 
    val x = ""
    val f = if (x == null) "x is null" else "not null"
}

scala> new Foo { override val x = "a" }.f
res10: String = x is null

scala> new Foo {}.f
res11: String = not null
Run Code Online (Sandbox Code Playgroud)

Scala FAQ中有完整的解释.摘抄:

当val被覆盖时,它自然不会被初始化多次.因此,虽然上面示例中的x2似乎在每个点都被定义,但事实并非如此:在构造超类时,重写的val似乎为null,抽象的val也是如此.

避免这种情况的一种简单方法是使用惰性val或def,如果被引用的val可能被覆盖.

此外,您可以使用-Xcheckinit编译器标志来警告您可能出现的初始化错误.