scala泛型方法重写

时间:2011-01-07 15:09:26

标签: scala override generic-method

我有一个抽象类:

abstract class Foo(...){
   def bar1(f : Foo) : Boolean
   def bar2(f : Foo) : Foo
}

多个类扩展Foo并覆盖方法

class FooImpl(...) extends Foo{
    override def bar1(f : Foo) : Boolean {
        ...
    }
    override def bar2(f : Foo) : Foo {
        ...
    }
} 

是否有可能使用泛型(或其他东西)使重写方法具有实现它的子类的参数类型?像这样:

class FooImpl(...) extends Foo{
    override def bar1(f : FooImpl) : Boolean {
        ...
    }
    override def bar2(f : FooImpl) : FooImpl {
        ...
    }
}

我正在考虑下面的内容,但这似乎不起作用......

abstract class Foo(...){
    def bar1[T <: Foo](f : T) : Boolean
    def bar2[T <: Foo](f : T) : T
}

class FooImpl(...) extends Foo{
    override def bar1[FooImpl](f : FooImpl) : Boolean {
       ...
    }
    override def bar2[FooImpl](f : FooImpl) : FooImpl{
       ...
    }
}

非常感谢任何帮助!

谢谢。

5 个答案:

答案 0 :(得分:20)

abstract class Foo{
   type T <: Foo
   def bar1(f:T):Boolean
   def bar2(f:T):T
}

class FooImpl extends Foo{
   type T = FooImpl
   override def bar1(f:FooImpl) = true
   override def bar2(f:FooImpl) = f
}

在此版本中,Foo的不同子类全部共享Foo作为超类,但保留bar2的返回值(或参数bar1或{ {1}})在一个设置中,您对对象的所有了解(假设它的名称为bar2)是obj,您需要使用类型Foo作为类型变量。

答案 1 :(得分:12)

为了让Ken Blum的第二个版本更好一点,你可以使用自我类型:

abstract class Foo[T] { self:T =>
   def bar1(f:T):Boolean
   def bar2(f:T):T
}

class FooImpl extends Foo[FooImpl]{
   override def bar1(f:FooImpl) = true
   override def bar2(f:FooImpl) = f
}

答案 2 :(得分:2)

T需要是您继承的Foo类的类型参数,而不是方法本身。

abstract class Foo[T <: Foo[T]]{
   def bar1(f:T):Boolean
   def bar2(f:T):T
}

class FooImpl extends Foo[FooImpl]{
   override def bar1(f:FooImpl) = true
   override def bar2(f:FooImpl) = f
}

Foo的不同子类在此版本的代码中实际上没有共同的超类型,因为它们从Foo的不同参数化扩展而来。当你需要使用常见的超类型时,可以使用引用Foo[T]的参数化方法,但我倾向于选择我在其他答案中发布的抽象类型解决方案,因为它不会泄漏泛型的细节所有其他必须处理Foos的功能。

答案 3 :(得分:1)

理想情况下,你要结合上面提到的东西,即

trait Foo[T <: Foo[T]] { self:T =>

“[T&lt;:Foo [T]]”表示T是Foo [T]的子类, 和“自我:T =&gt;”意味着Foo [T]是T的子类,并且一起告诉Foo [T]与T完全相同是一种奇怪的方式。

只有这样我才能使下面的代码编译并按预期工作:

trait Field[T <: Field[T]] { self:T =>

  def x2:T

  def +(that:T):T

  def *(n:BigInt) : T = {
    if(n == 1)
      this
    else if(n == 2)
      this.x2
    else if(n == 3)
      this + this.x2
    else {
      val p = (this * (n/2)).x2
      if (n%2==0)
        p
      else
        p + this
    }        
  }

}

答案 4 :(得分:0)

您可以参数化Foo以轻松完成某些效果:

abstract class Foo[F <: Foo[F]] { def f: F }
class Food extends Foo[Food] { def f = this }  // Yay!
class Fool extends Foo[Food] { def f = new Food }  // Uh-oh...

如果你想排除第二种情况,那么使用Scala中的当前功能就没有直接的方法。

此外,如果您在Foo中提供实际实施,那么您似乎想要的一些内容就没有意义。如果Foo承诺接受任何Foo,但你给它一个仅坚持Food的方法,如果你传递Foo的不同子类,它将会中断(例如Fool)。所以编译器不允许你这样做。

abstract class Foo { def bar(f: Foo) : Foo }
class Foot extends Foo { def bar(f: Foo) = this }   // Fine!
class Fool extends Foo { def bar(f: Fool) = this }   // No good!