假设我有以下特征
trait Foo[T] {
def overrideMe(other:Foo[T]) : Int
}
我希望能够做到
class Bar extends Foo[Int] {
override def overrideMe(other:Bar) : Int = other.BarFn
}
但它没有编译。原因是我希望overrideMe能够使用子类型的功能。我可以做类似
的事情class Bar extends Foo[Int] {
override def overrideMe(other:Foo[Int]) : Int = {
other.asInstanceOf[Bar].BarFn
}
但这看起来不太好。
是否可以在特征中说明虚拟函数可以用子类型覆盖?
修改 的 @agilesteel这几乎有效,但如果我在另一个只依赖于特性Foo的类中有一个函数,我会遇到麻烦
class Test[T] {
def callOverrideMe(a : Foo[T], b : Foo[T] ) : Int = a.overrideMe(b)
}
我收到编译错误:类型不匹配;发现b.type(底层类型为foo.Foo [T])需要a.SubType
答案 0 :(得分:7)
trait Foo[T] {
type TheSubType <: Foo[T]
def overrideMe(other: TheSubType) : Int
}
class Bar extends Foo[Int] {
type TheSubType = Bar
override def overrideMe(other: Bar) : Int = other.barFn
def barFn = 10
}
答案 1 :(得分:6)
class Test[T] {
def callOverrideMe(a : Foo[T], b : Foo[T] ) : Int = a.overrideMe(b)
}
当然,您无法使用此签名。考虑一下
class Baz extends Foo[Int] {...}
new Test[Int].callOverrideMe(new Bar, new Baz)
这应该与new Bar.overrideMe(new Baz)
相同,但您不希望它编译!
您可以使用curiously recurring template pattern:
trait Foo[T, Sub <: Foo[T, Sub]] {
def overrideMe(other:Sub) : Int
}
class Bar extends Foo[Int, Bar] {
override def overrideMe(other:Bar) : Int = other.BarFn
}
class Test[T] {
def callOverrideMe[Sub <: Foo[T, Sub]](a : Sub, b : Sub) : Int = a.overrideMe(b)
}
我想要实现的是依赖于特征的算法,然后在子类型中实现一些功能。还有其他好的设计模式吗?
查看Scalaz类型类。例如。 https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Equal.scala
答案 2 :(得分:4)
对于问题的第二部分,agilesteel的解决方案可以使用类型细化,
trait Foo[T] {
type R <: Foo[T]
def overrideMe(other: R) : Int
}
class Bar extends Foo[Int] {
type R = Bar
override def overrideMe(other: Bar) : Int = other.barFn
def barFn = 10
}
def callOverrideMe[T, R0 <: Foo[T]{type R = R0}](a : R0, b : R0) : Int = {
a.overrideMe(b)
}
在T
中推断类型callOverrideMe
可能有困难。改进类型推断的一种方法是使R
更高的kinded ---即,给它自己的类型参数T
。
此解决方案基本上等同于Alexey Romanov,并演示了如何将抽象类型表示为类型参数。