9.7. Ograniczenia typów kowariantnych i kontrawariantnych

Nie każdy typ ogólny może być kowariantny i nie każdy może być kontrawariantny ze względu na określone parametry typu.

Plik ReaderWriter1.scala:
class ReaderWriter[+T](private var content: T) {
  def read: T = content
  def write(x: T) { content = x }
}
Plik ReaderWriter2.scala:
class ReaderWriter[-T](private var content: T) {
  def read: T = content
  def write(x: T) { content = x }
}

Przykłady z plików ReaderWriter1.scala oraz ReaderWriter2.scala nie kompilują się, gdyż klasy w nich zdefiniowane nie spełniają warunków pozwalających na zdefiniowanie parametrów typu jako kowariantnych i kontrawariantnych.

$ scalac ReaderWriter1.scala
ReaderWriter1.scala:1: error: covariant type T occurs in contravariant position in type T of value content_=
class ReaderWriter[+T](private var content: T) {
      ^
ReaderWriter1.scala:3: error: covariant type T occurs in contravariant position in type T of value x
  def write(x: T) { content = x }
            ^
two errors found

$ scalac ReaderWriter2.scala
ReaderWriter2.scala:1: error: contravariant type T occurs in covariant position in type => T of method content
class ReaderWriter[-T](private var content: T) {
                                   ^
ReaderWriter2.scala:2: error: contravariant type T occurs in covariant position in type => T of method read
  def read: T = content
      ^
two errors found

Jakie zatem warunki musi spełniać parametr typu, aby mógł być określony jako kowariantny albo kontrawariantny? Istnieją określone pozycje w definicji typu ogólnego, w których może być użyty typ kowariantny oraz istnieją pozycje, w których może być użyty typ kontrawariantny. Te pierwsze są określane jako pozycje kowariantne, a te drugie jako pozycje kontrawariantne. Jeśli typ kowariantny lub kontrawariantny zostanie użyty w pozycji, w której nie może być użyty, to kompilator powiadomi nas o tym komunikatem błędu. Powyższe przykłady kompilacji plików ReaderWriter1.scala i ReaderWriter2.scala pokazują takie komunikaty. W pierwszym przypadku kompilator protestuje, gdyż nastąpiła próba użycia kowariantnego typu T w pozycji kontrawariantnej, natomiast w drugim dlatego, że nastąpiła próba użycia kontrawariantnego typu T w pozycji kowariantnej.

Specyfikacja języka Scala opisuje zasady dotyczące pozycji kowariantnych i kontrawariantnych w punkcie 4.5.

Język programowania Scala Wydanie 2. Copyright © Grzegorz Balcerek 2016

Licencja Creative Commons

Ten utwór jest dostępny na licencji Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowe.

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.