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



我正在使用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正在使用Impl类中实现foo方法。
同样,Impl类扩展了类A(类Impl的声明中with A)。

这不是循环的吗?
怎么可能?

谢谢。

从编译的角度来看,一切都检查出来了。Base要求无论谁扩展它,它都foo实现,这就是Impl所做的。允许特质A使用foo,因为它扩展了Base。一切都清楚了。

但是,我看到你的困惑。不过,我不会真正称它为循环;它更像是在启动之前使用某些东西(fooA中),在它被启动之前(在Impl中)。这样做的原因是因为您使用了def.编译器知道这个值稍后会可用(因为如果在编译过程的其余部分找不到它,它就会中断),它只是说"我知道它在调用时可用(假设编译成功),它是一个def,这意味着我将在那里计算它。所以我现在不需要这样做"。

但是,如果您使用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。

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

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

如果有多个实现(例如在特征A中),则顺序将基于线性化(见 https://stackoverflow.com/a/34243727/1547734)

最新更新