20.6. Ograniczenia widoku

Parametr zadeklarowany na liście parametrów implicit może definiować niejawną konwersję jednego typu na drugi. Taka sytuacja ma miejsce w definicji metody print1 z pliku ViewBounds1.scala.

Plik ViewBounds1.scala:
trait Show { def show:String }
object Show {
  implicit class ShowDouble(x: Double) extends Show {
    def show = f"$x%.2f"
  }
  implicit class ShowSymbol(x: Symbol) extends Show {
    def show = ":" + x.name
  }
}
object ShowUtil {
  def print1[T](value: T)(implicit s: T => Show) = print(value.show)
  def print2[T <% Show](value: T) = print(value.show)
}

Przeanalizujmy dokładniej cały przykład. Cecha Show definiuje metodę show, która zwraca wartość tekstową. Obiekt towarzyszący tej cechy zawiera definicje dwóch klas definiujących niejawne konwersje z typów Double i Symbol na typ Show. Metoda print1 ma na liście parametrów niejawnych parametr, który ma typ odpowiadający niejawnej konwersji z typu T na typ Show. W ciele metody znajduje się wywołanie metody show na obiekcie value typu T. Dzięki niejawnej konwersji reprezentowanej przez parametr s, to wywołanie kompiluje się, mimo że typ T nie musi zawierać metody show. Zauważmy, że taka definicja metody print1 nakłada dodatkowe ograniczenie na typ parametru T — mianowicie takie, że musi być dostępna niejawna konwersja z typu T na typ Show. Definicja metody print2 korzysta z innego sposobu zapisu analogicznego ograniczenia dotyczącego parametru typu T. Ten skrócony sposób zapisu wykorzystuje tak zwane ograniczenie widoku. Ograniczenie widoku B parametru typu A oznaczane jest jako A <% B i oznacza, że parametrowi A może odpowiadać dowolny typ, który może być przekształcony na typ B za pomocą niejawnej konwersji, czyli innymi słowy parametrowi A może odpowiadać typ, dla którego dostępny jest widok przekształcający go na typ B. Metoda zawierająca ograniczenie widoku A <% B jest odpowiednikiem metody, która ma parametr A bez tego ograniczenia, ale za to ma na liście parametrów niejawnych dodatkowy parametr definiujący konwersję z A na B. Taka relacja zachodzi między metodami print1 i print2. Obie metody działają analogicznie.

scala> ShowUtil.print1(2.0)
2,00
scala> ShowUtil.print1('abc)
:abc
scala> ShowUtil.print2(2.0)
2,00
scala> ShowUtil.print2('abc)
:abc

W obiekcie ShowUtil zdefiniowane są niejawne konwersje z typów Double i Symbol na Show, ale nie ma niejawnej konwersji z typu Int na Show. Z tego powodu poniższe próby wywołania metod print1 i print2, w której metodom tym przekazywane są wartości typu Int, nie kompilują się.

scala> ShowUtil.print1(2)
<console>:11: error: No implicit view available from Int => Show.
       ShowUtil.print1(2)
                      ^

scala> ShowUtil.print2(2)
<console>:11: error: No implicit view available from Int => Show.
       ShowUtil.print2(2)
                      ^

Ogranicznie widoku może być również zastosowane w przypadku parametrów typu w klasach (ale nie w cechach, które nie mają parametrów konstruktora i w związku z tym nie mogą mieć parametrów niejawnych). Plik ViewBounds2.scala przedstawia definicję klasy ShowUtils2, która ma parametr T z ograniczeniem widoku.

Plik ViewBounds2.scala:
class ShowUtil2[T <% Show](value: T) {
  def print2 = print(value.show)
}

Poniższe polecenia ilustrują użycie tej klasy.

scala> (new ShowUtil2(2.0)).print2
2,00
scala> (new ShowUtil2('abc)).print2
:abc

Specyfikacja języka Scala opisuje ograniczenia widoku w punkcie 7.4.

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.