9.1. Typy zawierające parametry
Definicje klas i cech w języku Scala mogą zawierać parametry typu. Parametry te umieszcza się w postaci listy identyfikatorów oddzielonych przecinkami, zawartej w nawiasach kwadratowych i umieszczonej po nazwie klasy lub cechy. Tak zdefiniowane parametry można następnie używać w ciele klasy/cechy. Klasy lub cechy zawierające parametry typu będziemy nazywać typami ogólnymi. Definicja klasy Box, z pliku TypeParameters1.scala, zawiera parametr typu, nazwany T.
Plik TypeParameters1.scala: class Box[T](val content: T) { override def toString = "[" + content + "]" }
Parametr T jest zadeklarowany w nawiasach kwadratowych umieszczonych po nazwie klasy. Następnie jest użyty w deklaracji parametru content. Instancję klasy Box możemy utworzyć następująco.
scala> val a = new Box[Int](5) a: Box[Int] = [5]
Wyrażenie tworzące instancję klasy zawiera, po nazwie klasy, nawiasy kwadratowe z umieszczoną wewnątrz nazwą typu. W tym przypadku jest to typ Int. Utworzony obiekt jest typu Box[Int], a typem wartości content jest Int.
scala> a.content res0: Int = 5
Typ argumentu konstruktora użytego w wyrażeniu tworzącym instancję klasy Box nie może być w konflikcie z typem zadeklarowanym w nawiasach kwadratowych. Poniższe wyrażenie jest błędne, gdyż argument typu Symbol nie odpowiada wymaganemu typowi Int.
scala> val b = new Box[Int]('abc)
<console>:10: error: type mismatch;
found : Symbol
required: Int
val b = new Box[Int]('abc)
^
Jeśli nawiasy klamrowe i specyfikacja typu zostaną pominięte w wyrażeniu tworzącym nową instancję typu ogólnego, to kompilator może podjąć próbę wywnioskowania jakie typy mają zostać użyte w miejscu parametrów typu.
scala> val c = new Box('abc)
c: Box[Symbol] = ['abc]
W powyższym przykładzie nawiasy kwadratowe wraz z zawartością zostały pominięte w wyrażeniu tworzącym nowy obiekt. Mimo to Scala poradziła sobie z utworzeniem obiektu. Typ parametru T został wywnioskowany i ustalony na Symbol na podstawie wartości argumentu konstruktora.
Plik TypeParameters2.scala zawiera definicję klasy mającej dwa parametry typu.
Plik TypeParameters2.scala: class PairBox[A,B](val a: A, val b: B) { override def toString = "[" + a + "," + b + "]" }
Poniżej przedstawione są przykładowe wyrażenia tworzące instancje tej klasy.
scala> val d = new PairBox[Int,Double](4,6.7)
d: PairBox[Int,Double] = [4,6.7]
scala> val e = new PairBox('a,4.5f)
e: PairBox[Symbol,Float] = ['a,4.5]
scala> val f = new PairBox(1,2)
f: PairBox[Int,Int] = [1,2]
Ostatni z przykładów ilustruje to, że nie jest błędem użycie tego samego typu w przypadku dwóch różnych parametrów typu. W tym przykładzie oba parametry — zarówno A, jak i B — przyjmują wartość Int.
Jeśli parametry typu zostają umieszczone w sposób jawny w wyrażeniu tworzącym instancję, to muszą być podane wszystkie. Natomiast jeśli zostają pominięte, to również muszą być pominięte wszystkie. Błędem jest próba jawnej deklaracji tylko części parametrów, jak w poniższym przykładzie.
scala> val g = new PairBox[Int](1,"ac")
<console>:10: error: wrong number of type arguments for PairBox, should be 2
val g = new PairBox[Int](1,"ac")
^
Typ zawierający dwa parametry może być zapisany jako tak zwany typ infiksowy. Deklaracja typu infiksowego ma postać T x S, co jest odpowiednikiem zapisu x[T,S]. Poniższy przykład ilustruje użycie klasy PairBox w deklaracji typu infiksowego.
scala> val h: Int PairBox Long = new PairBox(5, 7L) h: PairBox[Int,Long] = [5,7]
![]() | Specyfikacja języka Scala opisuje typy zawierające parametry w punkcie 3.2.4, typy infiksowe w punkcie 3.2.8, a parametry typu w punkcie 4.4. |
Plik TypeParameters1.scala:
class Box[T](val content: T) {
override def toString = "[" + content + "]"
}

