В то время как верхнее ограничение типа ограничивает тип до подтипа стороннего типа, нижнее ограничение типа объявляют тип супертипом стороннего типа. Термин 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(EuropeanSwallow())
Node[Bird]
может быть присвоен africanSwallowList
, но затем может добавлять и EuropeanSwallow
.
Contributors to this page:
Contents
- Введение
- Основы
- Единобразие типов
- Классы
- Значения Параметров По умолчанию
- Именованные Аргументы
- Трейты
- Кортежи
- Композиция классов с трейтами
- Функции Высшего Порядка
- Вложенные Методы
- Множественные списки параметров (Каррирование)
- Классы Образцы
- Сопоставление с примером
- Объекты Одиночки
- Регулярные Выражения
- Объект Экстрактор
- Сложные for-выражения
- Обобщенные Классы
- Вариантность
- Верхнее Ограничение Типа
- Нижнее Ограничение Типа
- Внутренние классы
- Члены Абстрактного Типа
- Составные Типы
- Самоописываемые типы
- Неявные Параметры
- Неявные Преобразования
- Полиморфные методы
- Выведение Типа
- Операторы
- Вызов по имени
- Аннотации
- Пакеты и Импорт
- Объекты Пакета