繁体   English   中英

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

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

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

谢谢。

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

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

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

从编译的角度来看,一切都可以检出。 Base要求任何人扩展foo的实现,而Impl就是这样做的。 特质A被允许使用foo因为它扩展了Base 一切都清楚了。

但是,我看到您的困惑。 我不会真的称其为循环。 它更像是在Impl之前(在Impl )使用某种东西( A foo )。 之所以可行,是因为您使用了def 编译器知道此值以后会可用(因为如果在其余的编译过程中找不到该值,它将中断),并且只是说“我知道在调用该值时该值将可用(给定)编译成功),并且它是一个def ,这意味着我将在那儿进行计算。因此,我现在不需要这样做。”

但是,如果使用val ,则fooA那一点被初始化因此您将获得该初始值,对于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具有相同的效果(它也是lazy计算的,只是在第一次使用时它只会被计算一次),因此修改上面的代码以override lazy val foo: Int = 42将导致在打印42。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM