型パラメータの変位指定(variance)
型パラメータで型の横に共変(+), 反変(-)の変位アノテーションを付けて変位指定ができる。
変位指定アノテーションを付けない場合は非変(nonvariant)になる。
どのパラメータ型を渡せるかの3種類の規則を指定。
共変(covariant)
scala> class Foo[+T](val a: T) defined class Foo scala> def bar(b: Foo[AnyVal]) = println(b.a) bar: (b: Foo[AnyVal])Unit scala> bar(new Foo[AnyVal](1)) 1 scala> bar(new Foo[Int](1)) 1 scala> bar(new Foo[Any](1)) <console>:10: error: type mismatch; found : Foo[Any] required: Foo[AnyVal] bar(new Foo[Any](1)) ^
- T型とTのサブ型は指定できるが、T のスーパー型は指定できない。
- ScalaのListの定義は共変。List[Int] は Lint[Any] の引数を受け取るメソッドに指定できる。
- イミュータブルなコレクションの型パラメータは共変が便利。
sealed abstract class List[+A] extends LinearSeq[A] with Product with GenericTraversableTemplate[A, List] with LinearSeqOptimized[A, List[A]] { ..snip..
非変(nonvariant)
scala> class Foo2[T](val a: T) defined class Foo2 scala> def bar2(b: Foo2[AnyVal]) = println(b.a) bar: (b: Foo2[AnyVal])Unit scala> bar2(new Foo2[AnyVal](1)) 1 scala> bar2(new Foo2[Int](1)) <console>:10: error: type mismatch; found : Foo2[Int] required: Foo2[AnyVal] Note: Int <: AnyVal, but class Foo2 is invariant in type T. You may wish to define T as +T instead. (SLS 4.5) bar(new Foo2[Int](1)) ^ scala> bar2(new Foo2[Any](1)) <console>:10: error: type mismatch; found : Foo2[Any] required: Foo2[AnyVal] Note: Any >: AnyVal, but class Foo2 is invariant in type T. You may wish to define T as -T instead. (SLS 4.5) bar2(new Foo2[Any](1)) ^
Scala の ArrayBuffer の定義は非変。
ミュータブルコレクションの型パラメータを非変にしておくと同じ型しかパラメータ型として指定できない制約をかけることができる。
class ArrayBuffer[A](override protected val initialSize: Int) extends Buffer[A] ..snip..
javaでは配列が共変でコレクションは非変。
反変(contravariant)
scala> class Foo3[-T] defined class Foo3 scala> class T1 defined class T1 scala> class T2 extends T1 defined class T2 scala> class T3 extends T2 defined class T3 scala> def bar3(a: Foo3[T2]) = println(a) bar3: (a: Foo3[T2])Unit scala> bar3(new Foo3[T1]) $line1.$read$$iw$$iw$Foo3@1ad9b0f scala> bar3(new Foo3[T2]) $line1.$read$$iw$$iw$Foo3@2445d7 scala> bar3(new Foo3[T3]) <console>:13: error: type mismatch; found : Foo3[T3] required: Foo3[T2] bar3(new Foo3[T3]) ^
関数(変換処理)の型の入力は反変、出力は共変 trait Funtcion1[-T1, +R] extends AnyRef