当覆盖一个特征时,为什么价值很奇怪?

Fre*_*ind 10 scala traits

演示scala代码:

trait A {
  val a = 3
  val b = a + 2
}

trait B extends A {
  override val a = 10
}

object X extends B

println(X.b)
Run Code Online (Sandbox Code Playgroud)

它打印价值:2,为什么不是512

kir*_*uku 13

要回答原因:

在Scala中你写的时候

class A {
  val a = 2
}
Run Code Online (Sandbox Code Playgroud)

该值在类的构造函数中初始化(相同的行为适用于特征和对象).此外,超类在子类之前初始化.这会导致您的用例出现以下行为:

B是创建的(内存是保留的),有两个变量a,b其值为0.现在A调用构造函数.因为a在子类中被覆盖并且由于Scalas动态绑定性质,它不会被赋值为2,而是具有子类的值.你想成为10,但因为这个赋值发生在B(尚未调用)的构造函数中,所以分配了默认值0.现在,b被分配.因为它没有被覆盖,所以a+2选择了值,其中a是0.因为构造函数A在这里完成,所以B可以调用构造函数,它将10分配给a.

因此,a是10并且b是2.

要回答如何对付此行为错误:

只要您不完全了解可能出现的问题,请不要使用val.使用defs或lazy val代替,值不会在类的构造函数中初始化,因此可以轻松覆盖.如果你绝对需要一个特质的val,那么让它成为最终的

可以将var标记为独立于子类的初始化,这可以通过以下方式完成var a: Type = _.这告诉编译器不要在定义类的构造函数中初始化此变量(但意味着该值需要保持可变).然后可以在子类中轻松分配它.当调用作为方法的超类的构造函数时,这很重要,它初始化var:

class A {
  f()
  def f() = ()
}

class B extends A {
  // don't initialize this var with anything else here or
  // the later assignment will be overwritten
  var b: Int = _
  override def f() =
    b = 5
}

new B().b // prints 5
Run Code Online (Sandbox Code Playgroud)