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されますが、 の戻り値(またはまたはbar2へのパラメーター) を、オブジェクト ( という名前だとしましょう) について知っていることだけが であるという設定で保持するには、 が必要です。タイプを変数のタイプとして使用します。bar1bar2objFooobj.T

于 2011-01-07T15:31:07.463 に答える
13

Ken Blum の 2 番目のバージョンをもう少し良くするために、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

TFooメソッド自体ではなく、継承元のクラスの型パラメーターである必要があります。

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

2 番目のケースを除外したい場合、Scala の現在の機能でそれを行う簡単な方法はありません。

また、 で実際の実装を行うと、必要と思われるものの一部が意味をなさない場合がありますFooFooが any を取ることを約束しているのにFoo、 a のみを主張するメソッドを指定した場合、 (例: )Foodの別のサブクラスを渡すと壊れます。したがって、コンパイラはそれを許可しません。FooFool

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 に答える