3

如果课程不是最终课程,则可以延长课程。

值有两种可能性:它可能被覆盖并且应该是惰性的,它可能不会被覆盖并且应该是最终的。

如果 val 是最终的 - 您可以假设对其进行的所有计算都将通过类层次结构进行。如果 val 可能被覆盖,你应该声明它是惰性的,因为在扩展后不会被破坏。您可以将 val 保留为原样,这不能保证它会以正确的方式扩展。

哪些用例意味着使用纯值?


没有惰性值的类初始化失败示例

abstract class A {
  lazy val x1 : String = throw new Exception()
  val x2 : String = "mom"
  val x3 : String = x1 + ", " + x2
  println("A: " + x3)
}
class B extends A {
  override lazy val x1: String = "hello"
  println("B: " + x3)
}
class C extends B {
  override val x2: String = "dad"
  println("C: " + x3)
}

测试它:

scala> new B
A: hello, mom
B: hello, mom
res8: B = B@7e2bd615

它可以工作,但进一步的子类化破坏了已经存在的功能

scala> new C
A: hello, null
B: hello, null
C: hello, null
res5: C = C@52a53948

在 x2 上设置惰性可以解决此问题:

abstract class A {
  lazy val x1 : String = throw new Exception()
  lazy val x2 : String = "mom"
  val x3 : String = x1 + ", " + x2
  println("A: " + x3)
}
class B extends A {
  override lazy val x1: String = "hello"
  println("B: " + x3)
}
class C extends B {
  override lazy val x2: String = "dad"
  println("C: " + x3)
}

正确的初始化顺序:

scala> new C
A: hello, dad
B: hello, dad
C: hello, dad
res6: C = C@5e970110
4

1 回答 1

3

基本上,你把它搞砸了。

问题不在于覆盖,问题在于您没有注意初始化事物的顺序。有办法让它起作用,也有办法让它不起作用,你选择了后者。这有效:

scala> class C extends { override val x2: String = "dad" } with B {
     |   println("C: " + x3)
     | }
defined class C

scala> new C
A: hello, dad
B: hello, dad
C: hello, dad
res0: C = C@356e3aaf
于 2012-08-23T16:12:59.050 回答