21

我有一个抽象类:

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{
       ...
    }
}

任何帮助深表感谢!

谢谢你。

4

5 回答 5

25
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保存返回值(或orbar2的参数)是它,你需要使用类型作为变量的类型。bar1bar2objFooobj.T

于 2011-01-07T15:31:07.463 回答
13

为了使 Ken Blum 的第二个版本更好一点,您可以使用 self 类型:

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
}
于 2011-01-07T20:06:44.060 回答
4

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 的函数。

于 2011-01-07T15:29:36.480 回答
1

理想情况下,您将上述内容结合起来,即

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

"[T <: Foo[T]]" 表示 T 是 Foo[T] 的子类,并且 "self:T =>" 表示 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
    }        
  }

}
于 2011-08-11T06:42:24.477 回答
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但你给它一个只坚持 a 的方法,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!
于 2011-01-07T15:40:53.317 回答