[英]Scala: Trait Mixin with 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
为什么无法编译所需的语法,是否有优雅的解决方案?
我的理解是,虽然错误消息可能令人困惑,但行为是正确的。 foo
在StackingTrait
被声明为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
)而不是使编写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
不能调用super.foo
(它没有意义并且会进入无限循环),但编译器不会就此发出警告。
您可以尝试使用示例中提到的 self-type,而不是扩展 trait。 https://docs.scala-lang.org/tour/self-types.html 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.