32

トレイト内で共変型パラメーターを使用して、次のようなケースクラスを構築しようとしています:

trait MyTrait[+T] {
  private case class MyClass(c: T)
}

コンパイラは次のように述べています。

error: covariant type T occurs in contravariant position in type T of value c

次に、次のことを試しましたが、うまくいきませんでした。

trait MyTrait[+T] {
  private case class MyClass[U <: T](c: U)
}

今回のエラーは次のとおりです。

error: covariant type T occurs in contravariant position in type >: Nothing <: T of type U

ここでTが共変の位置にある理由を誰かが説明し、この問題の解決策を提案できますか? どうも!

4

2 に答える 2

61

これはオブジェクト指向プログラミングの基本的な機能であり、当然のことながらあまり注目されていません。

コレクションがあるとしますC[+T]。その+T意味は、 if U <: T、 thenということですC[U] <: C[T]。けっこうだ。しかし、サブクラスであるとはどういう意味ですか? これは、元のクラスで機能したすべてのメソッドが機能することを意味します。したがって、メソッドがあるとしますm(t: T)。これは、あなたが何でも取りt、それで何かをすることができると言います. しかし、すべてではないかもしれない でC[U]しかできません。したがって、あなたは が のサブクラスであるという主張に即座に反論しました。そうではありません。ではできて ではできないことがあります。UTC[U]C[T]C[T]C[U]

さて、これをどのように回避しますか?

1 つのオプションは、クラスを不変にする (ドロップする+) ことです。もう 1 つのオプションは、メソッド パラメーターを使用する場合、任意のスーパークラスも許可することですm[S >: T](s: S)Tが に変更されてもU、大したことではありません。 のスーパークラスは のTスーパークラスでもUあり、メソッドは機能します。(ただし、そのようなことを処理できるようにするには、メソッドを変更する必要があります。)

ケースクラスを使用すると、不変にしない限り、それを正しくするのはさらに難しくなります。そうすることをお勧めし、ジェネリックとバリアンスを他の場所にプッシュすることをお勧めします。ただし、これがユースケースで機能することを確認するには、詳細を確認する必要があります。

于 2012-03-08T15:15:26.407 に答える
13

もうすぐです。ここ:

scala> trait MyTrait[+T] {
     |   private case class MyClass[U >: T](c: U)
     | }
defined trait MyTrait

つまりMyClass[Any]、すべてに有効ですT。それが、その位置で使用できない理由の根本ですがT、それを実証するには、現在の気分よりも多くのコードが必要です。:-)

于 2012-03-08T15:33:25.857 に答える