特征中的覆盖函数

时间:2011-08-22 20:20:50

标签: scala

假设我有以下特征

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

3 个答案:

答案 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,并演示了如何将抽象类型表示为类型参数。