Scala posiada wbudowaną obsługą klas parametryzowanych przez typy. Tego typu klasy generyczne są szczególnie użyteczne podczas tworzenia klas kolekcji.
Poniższy przykład demonstruje zastosowanie parametrów generycznych:
class Stack[T] { var elems: List[T] = Nil def push(x: T): Unit = elems = x :: elems def top: T = elems.head def pop(): Unit = { elems = elems.tail } }
Klasa Stack
modeluje zmienny stos zawierający elementy dowolnego typu T
. Parametr T
narzuca ograniczenie dla metod takie, że tylko elementy typu T
mogą zostać dodane do stosu. Podobnie metoda top
może zwrócić tylko elementy danego typu.
Przykłady zastosowania:
object GenericsTest extends App { val stack = new Stack[Int] stack.push(1) stack.push('a') println(stack.top) stack.pop() println(stack.top) }
Wyjściem tego programu będzie:
97 1
Uwaga: podtypowanie typów generycznych jest domyślnie określane jako invariant (niezmienne). Oznacza to, że mając stos znaków typu Stack[Char]
, nie można go użyć jako stos typu Stack[Int]
. Byłoby to błędne, ponieważ pozwalałoby to nam na wprowadzenie liczb całkowitych do stosu znaków. Zatem Stack[T]
jest tylko podtypem Stack[S]
jeżeli S = T
. Ponieważ jednak jest to dość ograniczające, Scala posiada mechanizm adnotacji parametrów typów pozwalający na kontrolę zachowania podtypowania typów generycznych.