はじめに
下記のテキストを通して、基本的な書き方を学びつつ、個人的に気になったことを検証していくメモ代わりです。
https://dwango.github.io/scala_text/basic.html
本当にありがとう、dwango様・・・
型パラメータ
- ざっくりまとめ
- 型パラメータを使用したクラス定義
-
class className[T]
など[]
内に型パラメータを記載
-
- 継承なく、同一の型(
A
,B
)に対して- 非変:
A = B
- 非変:
-
A
がB
を継承しているとき- 共変:
B = A
- 反変:
A = B
- 反変のメリットは不明・・・(要調査)
- 共変:
- 型パラメータを使用したクラス定義
クラス定義の文法
-
基本型
class クラス名[型パラメータ1, 型パラメータ2, ..., 型パラメータN](コンストラクタ引数1 :コンストラクタ引数1の型, コンストラクタ引数2 :コンストラクタ引数2の型, ...) { 0個以上のフィールドの定数またはメソッド定義 }
-
実際の使用例
scala> :paste // Entering paste mode (ctrl-D to finish) class Cell[A](var value: A) { def put(newValue: A): Unit = { value = newValue } def get(): A = value } val cell = new Cell[Int](1) println(cell.get()) cell.put(2) println(cell.get()) // Exiting paste mode, now interpreting. 1 2 defined class Cell cell: Cell[Int] = Cell@bf0b927
-
型パラメータが効いて、エラーになるパターン
scala> :paste // Entering paste mode (ctrl-D to finish) class Cell[A](var value: A) { def put(newValue: A): Unit = { value = newValue } def get(): A = value } val cell = new Cell[Int](1) cell.put("something") // Exiting paste mode, now interpreting. <console>:19: error: type mismatch; found : String("something") required: Int cell.put("something") ^
実用的な例
-
基本型に忠実に作成した場合
scala> :paste // Entering paste mode (ctrl-D to finish) class Pair[A, B](val a:A, val b:B) { override def toString(): String = "(" + a + "," + b + ")" } def divideFull(m: Int, n:Int): Pair[Int, Int] = new Pair[Int, Int](m/n, m%n) divideFull(7, 3) // Exiting paste mode, now interpreting. defined class Pair divideFull: (m: Int, n: Int)Pair[Int,Int] res4: Pair[Int,Int] = (2,1)
-
引数より推測できる場合
scala> :paste // Entering paste mode (ctrl-D to finish) class Pair[A, B](val a:A, val b:B) { override def toString(): String = "(" + a + "," + b + ")" } def divide(m: Int, n:Int): Pair[Int, Int] = new Pair(m/n, m%n) divide(7, 3) // Exiting paste mode, now interpreting. defined class Pair divide: (m: Int, n: Int)Pair[Int,Int] res5: Pair[Int,Int] = (2,1)
-
ちなみに、型指定じゃなくした場合
scala> :paste // Entering paste mode (ctrl-D to finish) class Pair[A, B](val a:A, val b:B) { override def toString(): String = "(" + a + "," + b + ")" } def divide(m: Int, n:Int): Pair = new Pair[Int, Int](m/n, m%n) divide(7, 3) // Exiting paste mode, now interpreting. <console>:13: error: class Pair takes type parameters def divide(m: Int, n:Int): Pair = new Pair[Int, Int](m/n, m%n) ^
- 型定義の場合は推測してくれない
変位指定(variance)
非変(invariant)
-
何も指定しなかった型パラメータは通常は非変(invariant)になる
val : G[A] = G[B]
- 上記ができる場合は、非変であり
A=B
である場合のみである
- 上記ができる場合は、非変であり
-
実例
-
代入できない場合
scala> val arr: Array[Any] = new Array[String](1) <console>:7: error: type mismatch; found : Array[String] required: Array[Any] Note: String <: Any, but class Array is invariant in type T. You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10) val arr: Array[Any] = new Array[String](1) ^
-
代入できる場合
scala> val arr: Array[String] = new Array[String](1) arr: Array[String] = Array(null)
-
共変(covariant)
-
A が B を継承しているときにのみ代入が許される性質
val : G[B] = G[A]
-
基本型
class G[+A]
-
実例
scala> :paste // Entering paste mode (ctrl-D to finish) class Pair[+A, +B](val a: A, val b: B) { override def toString(): String = "(" + a + "," + b + ")" } val pair: Pair[AnyRef, AnyRef] = new Pair[String, String]("foo", "bar") // Exiting paste mode, now interpreting. defined class Pair pair: Pair[AnyRef,AnyRef] = (foo,bar)
- Pairは作成時に値を与えたら後は変更できず、したがってArrayStoreExceptionのような例外が発生する余地がない
- 一般的には、一度作成したら変更できない(immutable)などの型パラメータは共変にしても多くの場合問題がない
反変(contravariant)
-
A が B を継承しているときにのみ代入が許される性質
val : G[A] = G[B]
-
基本型
class G[-A]
-
実例
scala> val x1: AnyRef => AnyRef = (x: String) => (x:AnyRef) <console>:7: error: type mismatch; found : String => AnyRef required: AnyRef => AnyRef val x1: AnyRef => AnyRef = (x: String) => (x:AnyRef) ^ scala> val x1: String => AnyRef = (x: AnyRef) => x x1: String => AnyRef = <function1>
-
単純に逆にしてみるとどうなる?
scala> :paste // Entering paste mode (ctrl-D to finish) class Pair[-A, -B](val a: A, val b: B) { override def toString(): String = "(" + a + "," + b + ")" } val pair: Pair[String, String] = new Pair[AnyRef, AnyRef]("foo", "bar") // Exiting paste mode, now interpreting. <console>:7: error: contravariant type A occurs in covariant position in type => A of value a class Pair[-A, -B](val a: A, val b: B) { ^ <console>:7: error: contravariant type B occurs in covariant position in type => B of value b class Pair[-A, -B](val a: A, val b: B) { ^
-
反変の使い所がわからないなー。。。- コメント参照
-