Scala:Trait Mixin与抽象基类

时间:2013-01-05 07:08:48

标签: scala mixins traits abstract-base-class

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

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

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

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

我想不出为什么不允许这样的语法的一个很好的理由; foo在逻辑上定义为Impl,因此在概念上对堆叠的排序保持不变。

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

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

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

2 个答案:

答案 0 :(得分:4)

我的理解是,虽然错误消息可能令人困惑,但行为是正确的。 foo中的abstract override被声明为StackingTrait,因此在混合StackingTrait的任何具体类中,必须有一个具体的(未标记为abstract)实现<{1}} 之前 foo(相对于线性化顺序)。这是因为StackingTrait在线性化顺序中引用了之前的特征,因此在混合super之前肯定需要foo的具体实现,或StackingTrait将是荒谬的。

执行此操作时:

super.foo

线性化顺序为class Impl extends Base with StackingTrait { def foo {} } &lt; - Base&lt; - StackingTraitImpl StackingTraitBase之前的唯一特征没有定义Base的具体实现。

但是当你这样做时:

foo

线性化顺序变为:traitImplHelper extends Base { def foo {} } class Impl extends ImplHelper with StackingTrait &lt; - Base&lt; - ImplHelper&lt; - StackingTrait 此处Impl包含ImplHelper的具体定义,并且在 foo之前绝对是

值得一提的是,如果您在StackingTrait之后混合ImplHelper(如在StackingTrait中),那么您将再次遇到同样的问题并且无法编译。

所以,这看起来与我相当一致。 我不知道如何按照您的意图进行编译。但是,如果您更关心的是更容易编写class Impl extends StackingTrait with ImplHelper(并且能够在那里定义Impl而不需要单独的类/特征),而不是简单地编写foo }或Base,你仍然可以这样做:

StackingTrait

就像在原始版本中一样,您强制每个具体类实现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(它没有意义并且会进入无限循环),编译器不会警告你。

答案 1 :(得分:0)

您可以尝试使用自类型,而不是扩展特征,如示例中所述。 https://docs.scala-lang.org/tour/self-types.html