9.2. Ograniczenia górne

Definicja typu ogólnego może zawierać ograniczenia dotyczące parametrów typu. Ograniczenie górne G typu T oznaczamy T <: G. W miejscu tak określonego parametru typu T można użyć typu G lub typu będącego jego podtypem. Poniżej przedstawiony jest przykład, w którym takie ograniczenie typu znajduje zastosowanie.

W pliku TypeParameters2.scala znajdują się definicje klas Person, która reprezentuje osobę oraz dziedziczących z niej klas Man, reprezentującej mężczyznę i Woman, reprezentującej kobietę.

Plik TypeParameters3.scala:
abstract class Person(val name: String)
class Man(name: String) extends Person(name)
class Woman(name: String) extends Person(name)

W pliku TypeParameters4.scala zdefiniowana jest klasa Greeting, służąca do drukowania na ekranie pozdrowień dla poszczególnych osób.

Plik TypeParameters4.scala:
class Greeting(greeting: String) {
  def apply(person: Person) = println(greeting+" "+person.name+"!")
}

Korzystając z klasy Greeting można tworzyć i używać obiekty generujące pozdrowienia.

scala> val hello = new Greeting("Hello")
hello: Greeting = Greeting@199c6b5

scala> hello(new Man("Peter"))
Hello Peter!

scala> hello(new Woman("Mary"))
Hello Mary!

Spróbujmy teraz utworzyć obiekt, którego pozdrowienia są skierowane do mężczyzn.

scala> val helloMr = new Greeting("Hello Mr.")
helloMr: Greeting = Greeting@423aa2

Niestety, tego obiektu można używać zarówno w przypadku obiektów reprezentujących mężczyzn, jak i kobiety.

scala> helloMr(new Man("Peter"))
Hello Mr. Peter!

scala> helloMr(new Woman("Mary"))
Hello Mr. Mary!

Plik TypeParameters5.scala zawiera definicję klasy Greeting2, zawierającą ograniczenie typów, jakie może przyjmować parametr metody apply.

Plik TypeParameters5.scala:
class Greeting2[T <: Person](greeting: String) {
  def apply(person: T) = println(greeting+" "+person.name+"!")
}

W metodzie apply znajduje się odwołanie do składowej o nazwie name parametru person typu T. To odwołanie jest prawidłowe, gdyż typ T jest ograniczony z góry klasą Person, a ta klasa ma zdefiniowaną składową o nazwie name. Możemy teraz utworzyć obiekt, który pozwoli na generowanie pozdrowień tylko dla mężczyzn.

scala> val helloMr2 = new Greeting2[Man]("Hello Mr.")
helloMr2: Greeting2[Man] = Greeting2@a9d961

scala> helloMr2(new Man("Peter"))
Hello Mr. Peter!
scala> helloMr2(new Woman("Mary"))
<console>:12: error: type mismatch;
 found   : Woman
 required: Man
       helloMr2(new Woman("Mary"))
                ^

Ostatnie z wyrażeń nie kompiluje się, gdyż metoda obiektu helloMr2 przyjmuje tylko obiekty należące do klasy Man lub do jej podklas, natomiast obiekt mary jest typu Woman.

Definicja obiektu helloMr2 jest prawidłowa, gdyż klasa Man jest podklasą klasy Person. Próba zdefiniowania obiektu klasy Greetings2 z użyciem jako parametru typu klasy, która nie dziedziczy z Person, nie udaje się.

scala> val hello3 = new Greeting2[Int]("Hello Int")
<console>:10: error: type arguments [Int] do not conform to class Greeting2's type parameter bounds [T <: Person]
       val hello3 = new Greeting2[Int]("Hello Int")
           ^
<console>:10: error: type arguments [Int] do not conform to class Greeting2's type parameter bounds [T <: Person]
       val hello3 = new Greeting2[Int]("Hello Int")
                        ^

Poniższy przykład pokazuje definicję obiektu hello4, w której nie została określona jawnie wartość parametru T. Kompilator przyjął, że wartością T jest Nothing. W konsekwencji, tak zdefiniowany obiekt nie może być użyty ani z obiektami reprezentującymi meżczyzn, ani z obiektami reprezentującymi kobiety.

scala> val hello4 = new Greeting2("Hello inferred")
hello4: Greeting2[Nothing] = Greeting2@84a8e1

scala> hello4(peter)
<console>:12: error: not found: value peter
       hello4(peter)
              ^

scala> hello4(mary)
<console>:12: error: not found: value mary
       hello4(mary)
              ^

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.