Scala Language
タイプ差異
サーチ…
共分散
+
記号は型パラメータを共変変数としてマークします。ここでは「 Producer
はA
上で共変です。
trait Producer[+A] {
def produce: A
}
共変タイプのパラメータは、「出力」タイプと考えることができます。 A
を共変量としてマークA
と、 Producer[X] <: Producer[Y]
がX <: Y
提供していることがX <: Y
ます。例えば、 Producer[Cat]
は有効なProducer[Animal]
です。生産されたすべてのネコも有効な動物です。
共変型パラメータは、反変(入力)位置に現れません。私たちが主張しているとして、次の例では、コンパイルされませんCo[Cat] <: Co[Animal]
が、 Co[Cat]
たdef handle(a: Cat): Unit
の任意扱うことができないAnimal
で必要とされるCo[Animal]
!
trait Co[+A] {
def produce: A
def handle(a: A): Unit
}
この制限を扱う1つのアプローチは、共変タイプパラメータで囲まれた型パラメータを使用することです。次の例では、 B
がA
スーパータイプであることがわかります。したがって、 Option[X]
のdef getOrElse[B >: X](b: => B): B
はX
任意のスーパータイプを受け入れることができるということをX <: Y
に対してOption[X] <: Option[Y]
- Option[Y]
必要とされるY
のスーパータイプを含む:
trait Option[+A] {
def getOrElse[B >: A](b: => B): B
}
不変性
デフォルトでは、すべての型パラメータは不変です - 与えられたtrait A[B]
、 " A
はB
上で不変です"と言います。これは、 A[Cat]
とA[Animal]
2つのパラメータを与えられた場合、 A[Cat] <: A[Animal]
でもA[Cat] >: A[Animal]
Cat
とAnimal
関係にかかわらず。
差異注釈は、このような関係を宣言する手段を提供し、関係が有効なままになるように型パラメータの使用に関する規則を課します。
コントラスト変動
-
記号は反復型の型パラメータを示します。ここでは、 " Handler
はA
反変です"と言っています。
trait Handler[-A] {
def handle(a: A): Unit
}
反変的型パラメータは、「入力」型と考えることができます。マーキングA
反変そのアサートとしてHandler[X] <: Handler[Y]
但しX >: Y
。例えば、 Handler[Animal]
は有効なHandler[Cat]
であり、 Handler[Animal]
はcatsも処理する必要があるためです。
反変的型パラメータは、共変(出力)位置に現れません。次の例は、 Contra[Animal] <: Contra[Cat]
宣言しているのでコンパイルされませんが、 Contra[Animal]
はdef produce: Animal
持っていますContra[Cat]
必要に応じて猫を生成することは保証されていないdef produce: Animal
!
trait Contra[-A] {
def handle(a: A): Unit
def produce: A
}
ただし、解決策を過負荷にするために、反動は逆反復型パラメータの型の特異性を逆に反転させますHandler[Animal]
はHandler[Cat]
より "より具体的"であるとみなされます。
型パラメータのメソッドをオーバーロードすることは不可能であるため、この動作は一般に暗黙の引数を解決する場合にのみ問題になります。次の例ではofCat
の戻り値の型がより具体的なofAnimal
、 ofAnimal
は使用されません。
implicit def ofAnimal: Handler[Animal] = ???
implicit def ofCat: Handler[Cat] = ???
implicitly[Handler[Cat]].handle(new Cat)
この動作は現在scala.math.Ordering
変更される予定であり、 scala.math.Ordering
は型パラメータT
不変である(例として)。 1つの回避策は、あなたのtypeclassを不変にすることと、指定された型のサブクラスに適用するイベントで暗黙の定義を型パラメータ化することです:
trait Person
object Person {
implicit def ordering[A <: Person]: Ordering[A] = ???
}
コレクションの共分散
コレクションは通常、要素タイプ*で共変なので、スーパータイプが必要な場合は、サブタイプのコレクションを渡すことができます。
trait Animal { def name: String }
case class Dog(name: String) extends Animal
object Animal {
def printAnimalNames(animals: Seq[Animal]) = {
animals.foreach(animal => println(animal.name))
}
}
val myDogs: Seq[Dog] = Seq(Dog("Curly"), Dog("Larry"), Dog("Moe"))
Animal.printAnimalNames(myDogs)
// Curly
// Larry
// Moe
それは魔法のようには見えないかもしれませんが、 Seq[Animal]
がその型パラメータで共変する高級型(ここではSeq
)という概念全体をSeq[Dog]
が受け入れるという事実は受け入れられます。
*
反例は、標準ライブラリのセット
不変形質上の共分散
1つのメソッドが共変の引数を受け入れるようにする方法もあります。これは、あなたが反変的な位置でT
を使用したいが、依然としてそれが共変しているので、必要かもしれない。
trait LocalVariance[T]{
/// ??? throws a NotImplementedError
def produce: T = ???
// the implicit evidence provided by the compiler confirms that S is a
// subtype of T.
def handle[S](s: S)(implicit evidence: S <:< T) = {
// and we can use the evidence to convert s into t.
val t: T = evidence(s)
???
}
}
trait A {}
trait B extends A {}
object Test {
val lv = new LocalVariance[A] {}
// now we can pass a B instead of an A.
lv.handle(new B {})
}