2012-03-08 3 views
31

なぜ反復的な位置にパラメータがありますか?私はそうのようなケースクラスを構築するために、形質内の共変の型パラメータを使用しようとしている

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

コンパイラは言う:

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

私は、次のことを試してみましたが、それはまたdidnの「トンの仕事:

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がここで共変な位置にある理由を説明し、この問題の解決策を提案できますか? Thx!

+0

あなたは本当にしたいことを説明できますか?なぜあなたはTが共変で不変でないことを望んでいますか? –

答えて

61

これは、オブジェクト指向プログラミングの基本的な特長であり、それはそれほど注目されません。

コレクションC[+T]があるとします。 +Tの意味は、U <: Tの場合はC[U] <: C[T]となります。けっこうだ。しかし、サブクラスとはどういう意味ですか?それは、すべてのメソッドは元のクラスで働いたを動作させる必要があることを意味します。だから、方法があるとします。m(t: T)これは、tを取って何かをすることができると言います。しかし、C[U]Uでしか行えません。すべてがTでない可能性があります。あなたはすぐに、C[U]C[T]のサブクラスであるという主張と矛盾しています。 ではなく、です。 C[T]でできることは、C[U]ではできません。

今、この問題をどのように回避しますか?

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

ケースクラスでは、それを不変にしない限り、それを正しく取得することはさらに困難です。私はそれを行い、ジェネリックスと分散を他の場所に押し込むことをお勧めします。しかし、私はこれがあなたのユースケースでうまくいくことを確かめるために、もっと詳細を見る必要があります。

+0

あなたの答えに感謝します。あなたの解決策は、この場合私のために働いていません。共分散を破棄してその特性を不変にすることはうまくいくだろうが、私がここで望むものではない。メソッド(あるいは私の場合はケースクラス)がスーパータイプを取ることも、満足できるものではありません。 私は、物事が事件のために正しくなるのがなぜ難しいのか不思議です。 _case_キーワードのない同じコードはうまく動作することに注意してください。 – lapislazuli

+2

@lapislazuli - ケースクラスにはそれらを作成するコンパニオンメソッドが含まれているので(上記の 'T'を引数として)、上記のメソッドの制限に従わなければなりません。 'case'を含まなければ、クラスは' T'を取るメソッドをインターフェースに含意しません。 –

+0

レックスありがとう、今私にとって意味がある! – lapislazuli

13

ほぼあります。ここで:MyClass[Any]はすべてTに対して有効であることを意味し

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

。それがその位置にTを使用することができない理由の根本にありますが、現時点では私が気分よりも多くのコードを必要としていることを実証しています。 :-)

関連する問題