1

2つのクラスAとBがあり、BがAのサブタイプであるとします。これは明らかに、より豊富なタイプ階層の一部にすぎませんが、関連性はないと思います。Aが階層のルートであると想定します。Aのリストを追跡するコレクションクラスCがあります。ただし、Cをジェネリックにしたいので、Bのみを保持し、Aを受け入れないインスタンスを作成できます。

class A(val c: C[A]) {
    c.addEntry(this)
}
class B(c: C[A]) extends A(c)
class C[T <: A]{
    val entries = new ArrayBuffer[T]()
    def addEntry(e: T) { entries += e }
}
object Generic {
    def main(args : Array[String]) {
        val c = new C[B]()
        new B(c)
    }
}

上記のコードは明らかにエラー「タイプの不一致:C [B]が見つかりました、行にC[A]が必要です」を示していnew B(c)ます。

これをどのように修正できるかわかりません。ArrayBufferはTで非バリアント型であるため、 TでCを共変にすることはできません(のようにC[+T <: A])。Cは共変ではないため、BのコンストラクターにC[B]を要求させることはできません。

ここで間違った木を吠えていますか?私は完全なScala初心者なので、アイデアやヒントが役立つかもしれません。ありがとうございました!

編集:基本的に、私が欲しいのは、コンパイラが両方を受け入れることです

val c = new C[B]()
new B(c)

val c = new C[A]()
new B(c)

しかし拒否します

val c = new C[B]()
new A(c)

CでのArrayBufferの入力をTではなくAに緩和することはおそらく可能です。したがって、それが役立つ場合は、addEntryメソッドでも同様です。

4

4 に答える 4

1

C[+T <: A]ArrayBufferはTで非バリアント型であるため、CをTで共変にすることはできません(のように)

これだけではありません。のタイプはaddEntryそれを禁止するのに十分です:

val a: A = ...
val b: B = ...

val cb: C[B] = ...

cb.addEntry(b) // works
cb.addEntry(a) // doesn't and shouldn't
于 2011-01-08T05:07:54.327 に答える
0

Aのインスタンスを追跡する場合は、すべてのBもAであるため、C[A]のインスタンスをBのコンストラクターに渡す必要があります。

def main(args : Array[String]) {
    val c = new C[A]()
    new B(c)
}

ただし、Bを追跡したい場合、AはBについて何も知らないため、これをAに委任することはできません。

全体として、私はあなたの問題がやや不適切であると感じています。

于 2011-01-08T17:23:23.993 に答える
0

ハッキーですが、うまくいくようです:

class A(val c: C[A]) {
  c.addEntry(this.asInstanceOf[c.X])
}

class B(c: C[B]) extends A(c)

class C[+T <: A] {
    type X <: T
    val entries = new ArrayBuffer[X]()
    def addEntry(e: X) { entries += e }
}

object Generic {
    def main(args : Array[String]) {
        val c = new C(){ type T = B }
        new B(c)
    }
}

もちろん、適切な解決策にも興味があります...

于 2011-01-08T14:00:32.827 に答える
0

可能だったとしましょう。次に、これを行うことができます:

class A(val c: C[A]) {
    c.addEntry(this)
}
class B(c: C[A]) extends A(c)
class C[+T <: A]{
    val entries: ArrayBuffer[T] @uncheckedVariance = new ArrayBuffer[T]()
    def addEntry(e: T @uncheckedVariance) { entries += e }
}
object Generic {
    def main(args : Array[String]) {
        // Everything's fine so far...
        val c = new C[B]()
        c.addEntry(new B(c))
        // but, suddenly...
        val ca: C[A] = c
        ca.addEntry(new A(ca))
        // a problem appears!
        c.entries forall {
            case thing: B => true // ok
            case otherThing => false // not ok -- c now contains an A!
        }
    }
}

このコードを実行しようとすると、クラス キャスト例外が発生します。

編集

この要件を追加しました:

val c = new C[B]()
new B(c)

val c = new C[A]()
new B(c)

しかし、拒否します

val c = new C[B]()
new A(c)

ただし、Bが で初期化されていて、extends がC[B]指定されている場合、 は で初期化されるため、最後の要件に違反します。BABAC[B]

于 2011-01-10T13:16:07.737 に答える