Scala 如何强制子类使用更具体的返回类型重写继承的方法
考虑这个例子:Scala 如何强制子类使用更具体的返回类型重写继承的方法,scala,inheritance,overriding,Scala,Inheritance,Overriding,考虑这个例子: trait SpecialIntIterable extends Iterable[Int] { override def iterator: Iterator[Int] = ??? // implementation not relevant override def tail : SpecialIntIterable // plus some more methods... } class MyPrimeIterable extends SpecialI
trait SpecialIntIterable extends Iterable[Int] {
override def iterator: Iterator[Int] = ??? // implementation not relevant
override def tail : SpecialIntIterable
// plus some more methods...
}
class MyPrimeIterable extends SpecialIntIterable {
override def tail : SpecialIntIterable = ??? // implementation not relevant
}
我试图强制specialLiterable
的所有子类实现tail
,因此它再次返回specialLiterable
。这可能吗
当前我遇到以下编译器错误:
overriding method tail in trait SpecialIntIterable of type => de.cointrade.trader.SpecialIntIterable;
method tail in trait TraversableLike of type => Iterable[Int] has incompatible type;
(Note that method tail in trait SpecialIntIterable of type => de.cointrade.trader.SpecialIntIterable is abstract,
and is therefore overridden by concrete method tail in trait TraversableLike of type => Iterable[Int])
trait SpecialIntIterable extends Iterable[Int] {
Edit:我发现的一个解决方案是在specialLiterable
中引入一个抽象助手方法(例如称为rest
),并让tail
委托给它。但是,我想知道,如果没有一个额外的成员,这是否是可能的。在本文中,这被称为“相同结果类型原则”。在集合库中,这是通过模板类实现的,模板类的名称以Like
结尾,有时还混合了一些F-bound多态性。本质上,如果你想要一个看起来像这样的界面
trait Foo {
def makeResult: Foo // how enforce same-result-type ?
}
但您希望强制执行,而不是所有实现子类都返回自己类型的内容,您可以修改Foo
,如下所示:
trait FooLike[+Repr] {
def makeResult: Repr
}
然后将子类实现为
class Bar extends FooLike[Bar] {
def makeResult: Bar = ??? // now `Bar` is enforced as return type
}
在您的情况下,您可以尝试以下方法:
import scala.collection.IterableLike
import scala.collection.mutable.Builder
trait SpecialIntIterableLike[+Repr] extends IterableLike[Int, Repr]
abstract class SpecialIntIterable
extends Iterable[Int]
with SpecialIntIterableLike[SpecialIntIterable] {
override def newBuilder: Builder[Int, SpecialIntIterable] = ???
}
class MyPrimeIterable extends SpecialIntIterable with SpecialIntIterableLike[MyPrimeIterable] {
def iterator: Iterator[Int] = ???
override def tail : MyPrimeIterable = ??? // must override, otherwise compile-time errors
override def newBuilder: Builder[Int, MyPrimeIterable] = ??? // must override, otherwise compile-time errors
}
请注意,newBuilder
-方法必须被重写以解决冲突(这在上面链接的文档中提到)
编辑 即使您的
MyPrimeIterable
选择不扩展SpecialLiterableLike
,它仍然必须实现一个tail
,该tail至少返回一个SpecialLiterable
:
class MyOtherIterable extends SpecialIntIterable {
def iterator: Iterator[Int] = ???
override def newBuilder: Builder[Int, SpecialIntIterable] = ???
// def tail: Iterable[Int] = List(0) // won't compile
}
如果我们试图放松tail
的返回类型,它将无法编译,因为specialLiterable
扩展了specialLiterableLike[specialLiterable]
这类似于扩展,例如
IndexedSeq[X]
:您可以选择不实现IndexedSeqLike[X,MyType]
,因此“相同的结果类型”属性将稍微恶化,但tail
的结果类型仍然至少是IndexedSeq[X]
,而不是Iterable[X]
或比索引eq[X]
弱的东西 谢谢你的回答!然而,这似乎并不能真正解决我的问题MyPrimeIterable
仍然可以决定不实现tail,或者使用更通用的返回类型实现tail。顺便说一下,我不要求返回类型相同(即,MyPrimeIterable
),只要求是抽象的specialiterable
。在上面的示例中,MyPrimeIterable
不可能实现specialiterable
的tail
。它可以删除specialLiterable[MyPrimeLiterable]
,但不能删除tail
必须至少返回一个specialLiterable
的要求。还是我遗漏了什么?更新了我的答案,专门解决了tail
返回类型的界限。我想我现在明白了:如果MyOtherIterable
根本不覆盖tail
,它将自动获得正确的类型specialliterable
。我很困惑,因为我可以注释def tail…
行,但它仍然在编译。所以没有直接的方法“取消定义”一个超类的方法来强制子类重新实现它?或者至少强迫他们使用比超级实现的返回类型更具体的返回类型来实现它?@lex82 Ah,那么你想用扩展特性中的抽象实现来覆盖超级特性中的具体实现?不幸的是,这是错误的。我认为这与如何在线性化特征链中解决正确的方法实现有关:它简单地将线性化链自下而上,然后选择第一个实现的方法。似乎没有办法“抽象地重新阴影化”一个已经实现的方法……也许我误解了这个问题,因为我不理解“比什么更具体?”@Andreytukin,我的意思是比Iterable[Int]
更具体。