【问题标题】:In Scala, is it possible for parent trait to call method implemented in child class?在 Scala 中,父 trait 是否可以调用子类中实现的方法?
【发布时间】:2017-10-12 00:40:17
【问题描述】:

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

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

谢谢。

【问题讨论】:

    标签: scala inheritance methods overriding traits


    【解决方案1】:

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

    但是,我看到了你的困惑。不过,我不会真正称其为圆形。它更像是在初始化之前(在Impl 中)使用某些东西(A 中的foo)。之所以可行,是因为您使用了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。

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        猜你喜欢
        • 2019-07-22
        • 1970-01-01
        • 1970-01-01
        • 2012-08-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-13
        • 2023-04-09
        相关资源
        最近更新 更多