Scala в примерах: различия между версиями

Содержимое удалено Содержимое добавлено
→‎Нижние границы: — добавлен перевод параграфа
Строка 841:
 
== Нижние границы ==
 
Ранее мы видели верхние границы для типовых параметров. В объявлении типового параметра, например, <tt>T <: U</tt>, диапазон значений типового параметра <tt>T</tt> ограничен подтипами типа <tt>U</tt>. Симметрично этому в Scala есть нижние границы. В объявлении типового параметра <tt>T >: S</tt> диапазон значений типового параметра <tt>T</tt> ограничен ''супертипами'' типа <tt>S</tt>. (Можно также сочетать нижние и верхние границы, например, <tt>T >: S <: U</tt>.)
 
Используя нижние границы, можно обобщить метод <tt>push</tt> класса <tt>Stack</tt> следующим образом:
 
<font size=3><syntaxhighlight lang=Scala>
class Stack[+A] {
def push[B >: A](x: B): Stack[B] = new NonEmptyStack(x, this)
</syntaxhighlight></font>
 
Технически такой прием решает проблему с вариантностью, потому что теперь типовой параметр <tt>A</tt> больше не появляется как тип параметра метода <tt>push</tt>. Вместо этого он появляется как нижняя граница для другого типового параметра, который стоит в ковариантной позиции. Компилятор Scala допустит такое определение метода <tt>push</tt>.
 
На самом деле мы не просто решили техническую проблему вариантности, но и обобщили определение <tt>push</tt>. До этого мы могли применять этот метод только к тем элементам, чьи типы соответствуют объявленному типу стека. Теперь же мы можем вставлять в стек и элементы супертипа того типа, только и тип возвращаемого стека будет соответственно изменяться. Например, теперь мы можем вставлять <tt>AnyRef</tt> в стек элементов типа <tt>String</tt>, но полученный стек будет стеком <tt>AnyRef</tt>, а не стеком <tt>String</tt>!
 
В заключение скажем, что не нужно стесняться добавлять аннотации вариантности к вашим структурам данных, потому что это позволяет выражать богатые естественные связи типов и их подтипов. Компилятор заметит потенциальные проблемы корректности. Даже если приближения компилятора слишком консервативны, как в случае метода <tt>push</tt> класса <tt>Stack</tt>, этот прием часто может предоставить полезные обобщения методов.
 
== Крайние типы ==
== Кортежи ==