型パラメータ(type parameter)

Scala では、クラスを定義するときには決められないような型を持つことができる。この型は仮の名前をつけておき、実際にクラスのインスタンスを作るときに決まるようにする。これを型パラメータと呼ぶ。型パラメータはたとえば、中にどんな型が入るかわからないコンテナのようなクラスを作るのに役立つ。

型パラメータを使うには、クラス定義の時にクラス名の後に [ ] をつけてその中にパラメータ(習慣的に A,B,C…とつける)を書く。次の例は、データを出し入れできる Cell クラスだ。

scala> class Cell[A](var value: A) {
     |     def put(newValue: A): Unit = {
     |         value = newValue
     |     }
     |
     |     def get(): A = value
     | }
defined class Cell

この定義の中で、A が型パラメータ。この段階ではどんな型が入るのかはわからない。次のように使う。

scala> val cell = new Cell(2)
cell: Cell[Int] = Cell@716427b1

scala> cell.get()
res0: Int = 2

scala> cell.put(3)

scala> cell.get()
res2: Int = 3

定義時にはどんな型が入るかわからないけど、最初にインスタンスを作ったときに型が決まる(この例では Int)ので、違う型は put できない。

scala> cell.put("Hello")
<console>:13: error: type mismatch;
 found   : String("Hello")
 required: Int
       cell.put("Hello")
                ^

もちろん、インスタンス作成時には文字列でも何でも使える。

scala> val cell2 = new Cell("Andy")
cell2: Cell[String] = Cell@1ae85afc

scala> cell2.get()
res4: String = Andy

scala> cell2.put("Bill")

scala> cell2.get()
res6: String = Bill

型パラメータは複数とることができる。つぎの Pair クラスは2つの型パラメータをとっている。

scala> class Pair[A, B](val a: A, val b: B)
defined class Pair

A と B は別々の型でもいいし、同じ型でもいい。こんなふうに使う。

scala> val p1 = new Pair(1, "Andy")
p1: Pair[Int,String] = Pair@65c4462a

scala> p1.a
res7: Int = 1

scala> p1.b
res8: String = Andy

scala> val p2 = new Pair(2, 3)
p2: Pair[Int,Int] = Pair@404307dd

scala> p2.a
res9: Int = 2

scala> p2.b
res10: Int = 3