ジェネリッククラス
Info: JavaScript is currently disabled, code tabs will still work, but preferences will not be remembered.
ジェネリッククラスはパラメータとして型を1つ受け取るクラスです。それらはコレクションクラスで特に役立ちます。
ジェネリッククラスの定義
ジェネリッククラスは角カッコ[]の中にパラメータとして型を1つ受け取ります。
型パラメータの識別子として文字Aを使う習慣がありますが、任意のパラメータ名を使うことができます。
class Stack[A] {
private var elements: List[A] = Nil
def push(x: A): Unit =
elements = x :: elements
def peek: A = elements.head
def pop(): A = {
val currentTop = peek
elements = elements.tail
currentTop
}
}
このStackクラスの実装はパラメータとして任意の型Aを受け取ります。
これはメンバーのリストvar elements: List[A] = Nilが型Aの要素のみを格納できることを意味します。
手続きdef pushは型Aのオブジェクトのみを受け取ります
(注: elements = x :: elementsは、xを現在のelementsの先頭に追加した新しいリストをelementsに割り当て直します)。
ここで Nil は空の List であり、 null と混同してはいけません。
使い方
ジェネリッククラスを使うには、角カッコの中にAの代わりに型を入れます。
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop) // prints 2
println(stack.pop) // prints 1
インスタンスstackはIntのみを受け取ることができます。
しかしながら、型がサブタイプを持つ場合、それらは以下のように渡すことができます。
class Fruit
class Apple extends Fruit
class Banana extends Fruit
val stack = new Stack[Fruit]
val apple = new Apple
val banana = new Banana
stack.push(apple)
stack.push(banana)
クラスAppleとBananaは共にFruitを継承しています。そのためFruitのスタックにはappleとbananaのインスタンスを追加できます。
注意: ジェネリック型のサブタイプは*非変(invariant)*です。つまりStack[Char]型の文字スタックがあるとき、それをStack[Int]型の整数スタックとして使うことはできません。文字スタックに整数を入れることはできるので、このことは変に思えるかもしれません。結論としては、B = Aの場合に限り、Stack[A]はStack[B]の唯一のサブタイプとなります。これでは制限が強いので、ジェネリック型のサブタイプの振る舞いをコントロールするために、Scalaは型引数アノテーションの仕組みを提供します。