の違いは何ですか
[A <: B]
と
[+B]
Scalaで?
Q[A <: B]
クラスは、のサブクラスであるQ
任意のクラスを取ることができることを意味します。A
B
Q[+B]
は任意のクラスQ
を取ることができることを意味しますが、がのサブクラスである場合、はのサブクラスと見なされます。A
B
Q[A]
Q[B]
Q[+A <: B]
これは、クラスQ
がサブクラス関係のサブクラスのみを取得B
し、サブクラス関係を伝播できることを意味します。
1つ目は、一般的なことを実行したいが、の特定のメソッドセットに依存する必要がある場合に役立ちますB
。たとえば、メソッドを持つOutput
クラスがあるtoFile
場合、に渡すことができる任意のクラスでそのメソッドを使用できますQ
。
2つ目は、元のクラスと同じように動作するコレクションを作成する場合に役立ちます。取っB
てサブクラスを作成すると、期待される場所ならどこにでもA
渡すことができます。しかし、、、のコレクションを取得する場合、代わりにいつでも渡すことができるというのは本当ですか?一般的に、いいえ。これが間違っている場合があります。しかし、これは(共分散、共分散-次の-のサブクラスの継承関係)を使用して行うのが正しいことであると言えます。A
B
B
Q[B]
Q[A]
+B
Q
B
Rex Kerrの優れた答えを、さらにいくつかの例で拡張したいと思います。4つのクラスがあるとしましょう。
class Animal {}
class Dog extends Animal {}
class Car {}
class SportsCar extends Car {}
case class List[+B](elements: B*) {} // simplification; covariance like in original List
val animals: List[Animal] = List( new Dog(), new Animal() )
val cars: List[Car] = List ( new Car(), new SportsCar() )
ご覧のとおり、リストには動物が含まれているか車が含まれているかは関係ありません。リストの開発者は、たとえば車だけがリスト内に入ることができることを強制しませんでした。
さらに:
case class Shelter(animals: List[Animal]) {}
val animalShelter: Shelter = Shelter( List(new Animal()): List[Animal] )
val dogShelter: Shelter = Shelter( List(new Dog()): List[Dog] )
関数がパラメーターを期待している場合は、代わりに関数の引数としてList[Animal]
aを渡すこともできます。Listの共分散により、のサブクラスと見なされます。Listが不変の場合は機能しません。List[Dog]
List[Dog]
List[Animal]
case class Barn[A <: Animal](animals: A*) {}
val animalBarn: Barn[Animal] = Barn( new Dog(), new Animal() )
val carBarn = Barn( new SportsCar() )
/*
error: inferred type arguments [SportsCar] do not conform to method apply's type parameter bounds [A <: Animal]
val carBarn = Barn(new SportsCar())
^
*/
ご覧のとおり、バーンは動物専用のコレクションです。ここへの車の乗り入れは禁止されています。
私の理解のために:
1つ目はパラメーターの型境界であり、この場合は上限と下限の型境界があり、「Bのサブタイプである型パラメーターA(またはB自体)です。
2つ目は、クラス定義の分散注釈です。この場合、Bの共分散サブクラス化です。
Scala:+ Java:?T共変サブクラス化を拡張します
Scala:-Java:?スーパーT反変サブクラス化
この質問を調査しているときに、このブログ投稿を見つけました。圏論の理論的根拠を含むScala分散のさらに深い説明を提供します
http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/