繁体   English   中英

Scala:带有抽象基类的特征混合

[英]Scala: Trait Mixin with Abstract Base Class

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

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

使用以下语法实现子类会非常方便,但这不起作用,因为编译器说 foo 需要在重新编译时使用overrideabstract override声明,这是无效的,因为Impl是一个类。

class Impl extends Base with StackingTrait {
  def foo {}
}

我想不出为什么不允许这种语法的充分理由; foo 在逻辑上是用Impl定义的,因此堆叠发生的顺序在概念上保持不变。

注意:我发现这个解决方法可以有效地做我想做的事情,但是辅助类的必要性让我想要一个更好的解决方案。

class ImplHelper extends Base {
  def foo {}
}
class Impl extends ImplHelper with StackingTrait

为什么无法编译所需的语法,是否有优雅的解决方案?

我的理解是,虽然错误消息可能令人困惑,但行为是正确的。 fooStackingTrait被声明为abstract override ,因此在任何混合StackingTrait具体类中,必须StackingTrait之前(相对于线性化顺序)有一个foo的具体(未标记为abstract )实现。 这是因为super指的是线性化顺序中之前的 trait,所以在混入StackingTrait之前肯定需要有foo的具体实现,否则super.foo将是无意义的。

当你这样做时:

class Impl extends Base with StackingTrait {
  def foo {}
}

线性化顺序是Base <- StackingTrait <- Impl StackingTrait之前的唯一特征是Base并且Base没有定义foo的具体实现。

但是当你这样做时:

traitImplHelper extends Base {
  def foo {}
}
class Impl extends ImplHelper with StackingTrait

线性化顺序变为: Base <- ImplHelper <- StackingTrait <- Impl这里ImplHelper包含foo的具体定义,并且绝对StackingTrait之前

值得一提的是,如果您在StackingTrait之后混合了ImplHelper (就像在class Impl extends StackingTrait with ImplHelper ),您将再次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 (它没有意义并且会进入无限循环),但编译器不会就此发出警告。

您可以尝试使用示例中提到的 self-type,而不是扩展 trait。 https://docs.scala-lang.org/tour/self-types.html

暂无
暂无

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

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