Tour of Scala

Нижнее Ограничение Типа

Language

В то время как верхнее ограничение типа ограничивает тип до подтипа стороннего типа, нижнее ограничение типа объявляют тип супертипом стороннего типа. Термин B >: A выражает, то что параметр типа B или абстрактный тип B относится к супертипу типа A. В большинстве случаев A будет задавать тип класса, а B задавать тип метода.

Вот пример, где это полезно:

trait Node[+B] {
  def prepend(elem: B): Node[B]
}

case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
  def prepend(elem: B): ListNode[B] = ListNode(elem, this)
  def head: B = h
  def tail: Node[B] = t
}

case class Nil[+B]() extends Node[B] {
  def prepend(elem: B): ListNode[B] = ListNode(elem, this)
}

В данной программе реализован связанный список. Nil представляет пустой список. Класс ListNode - это узел, который содержит элемент типа B (head) и ссылку на остальную часть списка (tail). Класс Node и его подтипы ковариантны, потому что у нас указанно +B.

Однако эта программа не компилируется, потому что параметр elem в prepend имеет тип B, который мы объявили ковариантным. Так это не работает, потому что функции контрвариантны в типах своих параметров и ковариантны в типах своих результатов.

Чтобы исправить это, необходимо перевернуть вариантность типа параметра elem в prepend. Для этого мы вводим новый тип для параметра U, у которого тип B указан в качестве нижней границы типа.

trait Node[+B] {
  def prepend[U >: B](elem: U): Node[U]
}

case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
  def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)
  def head: B = h
  def tail: Node[B] = t
}

case class Nil[+B]() extends Node[B] {
  def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)
}

Теперь мы можем сделать следующее:

trait Bird
case class AfricanSwallow() extends Bird
case class EuropeanSwallow() extends Bird


val africanSwallowList= ListNode[AfricanSwallow](AfricanSwallow(), Nil())
val birdList: Node[Bird] = africanSwallowList
birdList.prepend(new EuropeanSwallow)

Node[Bird] может быть присвоен africanSwallowList , но затем может добавлять и EuropeanSwallow.

Contributors to this page: