Scala:使用抽象基类进行Trait混入

7

我有一个抽象基类 (Base),为它定义了一些堆叠特征 (StackingTrait)。

trait Base {
  def foo
}
trait StackingTrait extends Base {
  abstract override def foo { super.foo }
}

以下语法为实现子类非常方便,但不起作用,因为编译器指出 foo 需要在重新编译时使用 override 和 abstract override 声明,这是无效的,因为 Impl 是一个类。请注意保留 HTML 标记。
class Impl extends Base with StackingTrait {
  def foo {}
}

我想不出为什么这种语法会被禁止的好理由;foo在逻辑上是用Impl定义的,因此概念上发生的堆叠顺序保持不变。
注意: 我找到了一个解决方法,可以有效地实现我想要的效果,但需要帮助类,这让我想要更好的解决方案。
class ImplHelper extends Base {
  def foo {}
}
class Impl extends ImplHelper with StackingTrait

为什么期望的语法无法编译,有没有优雅的解决方案?
2个回答

4
我的理解是,虽然错误信息可能令人困惑,但行为是正确的。在StackingTrait中,foo被声明为abstract override,因此在任何混合了StackingTrait的具体类中,必须在StackingTrait之前(相对于线性化顺序)有一个具体的(未标记为abstract)实现foo。这是因为super指的是线性化顺序中紧接着的特质,所以在混入StackingTrait之前一定需要一个具体的foo实现,否则super.foo会毫无意义。
当你这样做时:
class Impl extends Base with StackingTrait {
  def foo {}
}

线性化顺序是 Base <- StackingTrait <- Impl。在 StackingTrait 之前唯一的 trait 是 Base,且 Base 没有定义 foo 的具体实现。
但是,当你执行以下操作时:
traitImplHelper extends Base {
  def foo {}
}
class Impl extends ImplHelper with StackingTrait

线性化顺序如下:Base <- ImplHelper <- StackingTrait <- Impl。这里ImplHelper包含了foo的具体定义,并且明确位于StackingTrait之前。
值得一提的是,如果你将ImplHelper放在StackingTrait之后(就像class Impl extends StackingTrait with ImplHelper),那么你仍然会遇到相同的问题,编译将失败。
所以,对我来说,这看起来相当一致。我不知道有什么方法可以使它按照你的意图编译。但是,如果你更关心让编写Impl更容易(并且能够在那里定义foo而不需要单独的类/特质),而不是让编写BaseStackingTrait更容易,你仍然可以这样做:
trait Base {
  protected def fooImpl
  def foo { fooImpl } 
}
trait StackingTrait extends Base {
  abstract override def foo { super.foo }
}

class Impl extends Base with StackingTrait {
  protected def fooImpl {}
}

就像在原始版本中,您强制每个具体类实现foo(以fooImpl的形式),这一次确实编译了。 这里的缺点是,虽然fooImpl不能调用super.foo(这没有意义并且会进入无限循环),但编译器不会警告您。


非常好的答案!我正要发布一个关于这种情况的问题。谢谢! - Mark Canlas
我也刚遇到了这个问题。线性化最终是正确的,但我意识到堆叠特质的真实世界目的是:您只能使用堆叠特质对常见抽象类/特质的现有具体实现进行修改。例如,有一个抽象类List和一个特质Mod扩展List。您不能只编写class Foo extends List with Mod。首先,您必须拥有一个具体的List,例如class LinkedList extends List,然后您可以编写class Bar extends LinkedList with Mod。希望这有意义。 - Adam Hošek
我忘了补充一点,这只涉及到具有“abstract override”方法的特质,以便清楚明白。如果没有这样的方法,似乎可以自由地混合特质。 - Adam Hošek
你试过这个吗?https://docs.scala-lang.org/tour/self-types.html - Adithya Puram

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接