質問

抽象クラスがあります:

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

どんな助けも大歓迎です!

ありがとうございました。

役に立ちましたか?

解決

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 また bar2)あなたがあなたのオブジェクトについて知っているすべての設定で(それが名前が付けられているとしましょう obj)それはaです Foo, 、タイプを使用する必要があります obj.T 変数のタイプとして。

他のヒント

Ken Blumの2番目のバージョンをもう少し良くするには、自己タイプを使用できます。

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
}

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] 共通のスーパータイプを使用する必要があるが、他の回答に投稿した抽象型ソリューションを好む傾向がある場合、genericsの詳細がfoosに対処しなければならない他のすべての機能に漏れないことを確認します。

理想的には、上記のことを組み合わせます

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

「[t <:foo [t]]」はtがfoo [t]のサブクラスであり、「self: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
    }        
  }

}

パラメーター化できます 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の現在の機能でそれを行う簡単な方法はありません。

また、あなたが望んでいると思われるもののいくつかは、あなたが実際の実装をしても意味がありません 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!
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top