Scalaジェネリックメソッドオーバーライド
-
30-09-2019 - |
質問
抽象クラスがあります:
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!