在 Scala 中,父特征是否可以调用子 class 中实现的方法?

In Scala, is it possible for parent trait to call method implemented in child class?

我正在使用 Scala,想知道为什么这段代码有效。

trait Base {
  def foo(x: Int): Int
}

trait A extends Base {
  def fooA(x: Int): Int = {
    foo(x)
  }
}

class Impl extends Base with A {
  override def foo(x: Int): Int = x
}

val a = new Impl
a.fooA(10)

a.fooA(10)的结果是10。
但是,在特征 A 中,方法 fooA 正在使用 foo 方法,该方法在 Impl class.
中实现 同样,Impl class 扩展了 class A(class Impl 的声明中的 with A)。

这不是圆形吗?
怎么可能?

谢谢。

这里没有什么特别的,方法foo定义在trait中允许在impl中调用和实现它。从哪里调用它并不重要。

调用如下 -> 调用 fooA.它仅在 impl 继承的 A 中定义。 fooA 调用 foo。 foo 在特征中定义,实现出现在 impl 中。这不是循环而是最基本的用法。

如果有多个实现(例如在特征 A 中),则顺序将基于线性化(参见

从编译的角度来看,一切都通过了。 Base 要求扩展它的人为 foo 实现,这就是 Impl 所做的。特征 A 被允许使用 foo 因为它扩展了 Base。一切都清楚了。

但是,我看到了你的困惑。不过,我不会真的称它为循环;它更像是在初始化(Impl 中)之前使用某些东西(A 中的foo)。之所以有效,是因为 您使用了 def。编译器知道这个值稍后可用(因为如果在编译过程的其余部分找不到它,它就会中断)并且它只是说 "I know it will be available at the point when it is invoked (given the compilation is successful), and it's a def, which means I will be calculating it then and there. So I don't need to do it now".

但是,如果您使用 valfoo 将在 A 中的那个点被初始化 ,因此您将获得该初始值, Interegers 为 0:

trait Base {
  val foo: Int
}

trait A extends Base {
  val fooA: Int = foo
}

class Impl extends Base with A {
  override val foo: Int = 42
}

val a = new Impl
println(a.fooA) // prints 0 although we wanted 42

注意lazy valdef的效果是一样的(也是偷懒计算的,只是在第一次使用的时候只会计算一次),所以修改上面override lazy val foo: Int = 42 的代码也会导致打印 42。