web-dev-qa-db-ja.com

ScalaのA <:Bと+ Bの違いは何ですか?

違いは何ですか

[A <: B]

そして

[+B]

scalaでは?

67
jsadfeew

Q[A <: B]は、クラスQAのサブクラスである任意のクラスBを取ることができることを意味します。

Q[+B]は、Qanyクラスを取ることができることを意味しますが、ABのサブクラスの場合、Q[A]Q[B]のサブクラスと見なされます。

Q[+A <: B]は、クラスQBのサブクラスのみを受け取り、サブクラスの関係を伝播できることを意味します。

1つ目は、一般的なことをしたいが、Bの特定のメソッドセットに依存する必要がある場合に便利です。たとえば、OutputクラスにtoFileメソッドが含まれている場合、Qに渡すことができる任意のクラスでそのメソッドを使用できます。

2番目は、元のクラスと同じように動作するコレクションを作成する場合に便利です。 Bを受け取り、サブクラスAを作成すると、Aが必要な場所であればどこでもBを渡すことができます。しかし、BQ[B]の-​​collectionを取る場合、代わりに常にQ[A]を渡すことができるのは本当ですか?一般に、いいえ。これが不適切な場合があります。しかし、これは+B(共分散; Q共変----Bのサブクラスの継承関係に従う)を使用して行うのが正しいことであると言えます。

167
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() )

ご覧のとおりListには、動物または車が含まれているかどうかは関係ありません。リストの開発者はそれを強制しませんでした。車のみがリスト内に入ることができます。

さらに:

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]パラメータを必要とする場合は、代わりに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())
                 ^
*/

ご覧のように納屋は、動物のみを対象としたコレクションです。ここには車は入れません。

45
mucaho

この質問を調査しているときに、このブログ投稿を見つけました。 Scala分散のカテゴリー理論における理論的根拠を含む)のさらに深い説明を与える

http://blogs.atlassian.com/2013/01/covariance-and-contravariance-in-scala/

2
Totoro

私の理解のために:


1つ目はパラメータタイプの境界です。この場合、上限と下限のタイプ境界は「BのサブタイプであるタイプパラメータA(またはB自体)」です。


2つ目は、クラス定義の分散アノテーションです。この例では、Bの共分散サブクラス化です。


Scala:+ Java:? T共変サブクラスを拡張します

Scala:-Java:?スーパーT反変サブクラス化

2
Michele