9.5. Kowariantne parametry typu
Nie każdy parametr typu ogólnego musi być niezmienniczy. Można poprzedzić parametr znakiem + co oznacza, że jest on kowariantny. Taka sytuacja ma miejsce w przypadku definicji klasy Reader z pliku Reader.scala i oznacza, że w przypadku klas A i rozszerzającej ją B, Reader[A] jest typem nadrzędnym dla Reader[B].
Plik Reader.scala: class Reader[+T](val content: T) { def read: T = content }
W związku z tym Reader[Int] jest podtypem Reader[Any], a zatem obiekt typu Reader[Int] może być użyty w miejscu, w którym wymagany jest obiekt typu Reader[Any].
scala> val intReader: Reader[Int] = new Reader(1234) intReader: Reader[Int] = Reader@1d14d74 scala> val anyReader: Reader[Any] = intReader anyReader: Reader[Any] = Reader@1d14d74 scala> anyReader.read res0: Any = 1234
Plik CovariantBox.scala przedstawia poprawioną definicję klasy modelującej pudełko z poprzedniego podrozdziału.
Plik CovariantBox.scala: class CovariantBox[+T](name: String, e: T) {
def take: T = { println("Taking "+e+" from the "+this) e } override def toString = name }
Definicja klasy CovariantBox różni się od definicji klasy Box
znakiem + poprzedzającym parametr T w nawiasach kwadratowych w
wierszu
. Taka definicja powoduje, że typ
CovariantBox[Paper] jest nadtypem CovariantBox[ColorPaper], a
zatem obiekt typu CovariantBox[ColorPaper] może być użyty w miejscu,
w którym wymagany jest obiekt typu CovariantBox[Paper].
scala> val yellowPaperBox: CovariantBox[Paper] =
| new CovariantBox[ColorPaper]("yellow paper box",
| new ColorPaper("yellow"))
yellowPaperBox: CovariantBox[Paper] = yellow paper box
Plik DrawingChild2.scala zawiera definicję klasy wykorzystującej typ CovariantBox[Paper] do zamodelowania pudełka.
Plik DrawingChild2.scala: class DrawingChild2(name: String, box: CovariantBox[Paper], wasteBin: WasteBin[Paper]) { def draw { val paper = box.take println("Drawing on "+paper) wasteBin.throwAway(paper) } override def toString = name }
Teraz możemy już utworzyć nowy obiekt reprezentujący dziecko rysujące na żółtych kartkach.
scala> val paperWasteBin = new WasteBin[Paper]("paper waste bin")
paperWasteBin: WasteBin[Paper] = paper waste bin
scala> val yellowPaperBox = new CovariantBox[ColorPaper](
| "yellow paper box",new ColorPaper("yellow"))
yellowPaperBox: CovariantBox[ColorPaper] = yellow paper box
scala> val john = new DrawingChild2("John",yellowPaperBox,paperWasteBin)
john: DrawingChild2 = John
scala> john.draw
Taking yellow paper from the yellow paper box
Drawing on yellow paper
Throwing away yellow paper into the paper waste bin
Plik Reader.scala:
class Reader[+T](val content: T) {
def read: T = content
}
