sie*_*ent 7 scala traits mixins abstract-base-class
我有一个抽象的基类(Base
),它有一些为它定义的堆栈特征(StackingTrait
).
trait Base {
def foo
}
trait StackingTrait extends Base {
abstract override def foo { super.foo }
}
Run Code Online (Sandbox Code Playgroud)
使用以下语法实现子类非常方便,但是这不起作用,因为编译器说foo需要声明,override
然后abstract override
重新编译,这是一个无效的因为Impl
是一个类.
class Impl extends Base with StackingTrait {
def foo {}
}
Run Code Online (Sandbox Code Playgroud)
我想不出为什么不允许这样的语法的一个很好的理由; foo在逻辑上被定义为Impl
使得在概念上发生堆叠的顺序保持不变.
注意:我发现这种解决方法可以有效地完成我想要的相同操作,但是帮助类的必要性使我想要一个更好的解决方案.
class ImplHelper extends Base {
def foo {}
}
class Impl extends ImplHelper with StackingTrait
Run Code Online (Sandbox Code Playgroud)
为什么没有编译所需的语法,是否有一个优雅的解决方案?
我的理解是,虽然错误消息可能令人困惑,但行为是正确的。
foo
被声明为abstract override
in StackingTrait
,因此在任何混合的具体类中StackingTrait
必须有beforeabstract
的具体(未标记为 )实现(相对于线性化顺序)。这是因为指的是线性化顺序中之前的特征,因此肯定需要混入before的具体实现,否则将是无意义的。foo
StackingTrait
super
foo
StackingTrait
super.foo
当你这样做时:
class Impl extends Base with StackingTrait {
def foo {}
}
Run Code Online (Sandbox Code Playgroud)
线性化顺序为Base
<- StackingTrait
<- Impl
。之前唯一的特征StackingTrait
是Base
并且Base
没有定义 的具体实现foo
。
但是当你这样做时:
traitImplHelper extends Base {
def foo {}
}
class Impl extends ImplHelper with StackingTrait
Run Code Online (Sandbox Code Playgroud)
线性化顺序变为:Base
<- ImplHelper
<- StackingTrait
<-Impl
这里ImplHelper
包含 的具体定义foo
,且肯定位于之前 StackingTrait
。
值得一提的是,如果您在ImplHelper
之后进行了混合StackingTrait
(如 中所示class Impl extends StackingTrait with ImplHelper
),您将再次遇到相同的问题并且编译失败。
所以,这对我来说看起来相当一致。我不知道有什么方法可以让它按照您的预期进行编译。但是,如果您更关心使其更易于编写Impl
(并且能够foo
在此处定义而不需要单独的类/特征)而不是使其易于编写Base
or 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 {}
}
Run Code Online (Sandbox Code Playgroud)
就像在原始版本中一样,您强制每个具体类实现foo
(以 的形式fooImpl
),这次它确实可以编译。这里的缺点是 whilefooImpl
不能调用super.foo
(它没有意义并且会进入无限循环),编译器不会警告您。
归档时间: |
|
查看次数: |
1804 次 |
最近记录: |