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

Содержимое удалено Содержимое добавлено
→‎Нижние границы: — добавлен перевод параграфа
→‎Крайние типы: — перевод параграфа
Строка 858:
 
== Крайние типы ==
 
Scala не позволяет параметризовать объекты по типам. Поэтому мы вначале определили обобщенный класс <tt>EmptyStack[A]</tt>, несмотря на то, что единственного значения, обозначающего пустые стеки произвольного типа, было бы достаточно. Для ковариантных стеков, впрочем, можно использовать следующую конструкцию:
 
<font size=3><syntaxhighlight lang=Scala>
object EmptyStack extends Stack[Nothing] { … }
</syntaxhighlight></font>
 
Нижний граничный тип <tt>Nothing</tt> не содержит значения, так что тип <tt>Stack[Nothing]</tt> выражает факт того, что в <tt>EmptyStack</tt> нет элементов. Помимо этого, <tt>Nothing</tt> является подтипом всех других типов. Заметьте, что для ковариантных стеков <tt>Stack[Nothing]</tt> — подтип <tt>Stack[T]</tt> для любого другого типа <tt>T</tt>. Поэтому можно использовать лишь единственный объект пустого стека в пользовательском коде. К примеру,
 
<font size=3><syntaxhighlight lang=Scala>
val s = EmptyStack.push("abc").push(new AnyRef())
</syntaxhighlight></font>
 
Давайте детально проанализируем присваивание типа этому выражению. Объект <tt>EmptyStack</tt> имеет тип <tt>Stack[Nothing]</tt>, у которого есть метод
 
<font size=3><syntaxhighlight lang=Scala>
push[B >: Nothing](elem: B): Stack[B]
</syntaxhighlight></font>
 
Локальный вывод типов определит, что типовой параметр <tt>B</tt> должен быть <tt>String</tt> в применении <tt>EmptyStack.push("abc")</tt>. Результирующий тип этого применения — <tt>Stack[String]</tt>, который, в свою очередь, имеет метод
<font size=3><syntaxhighlight lang=Scala>
push[B >: String](elem: B): Stack[B]
</syntaxhighlight></font>
 
Последняя часть определения значения, приведенного выше, это применение этого метода к <tt>'''new''' AnyRef()</tt>. Локальный вывод типов определит, что типовой параметр <tt>B</tt> должен на этот раз быть <tt>AnyRef</tt>, с результирующим типом <tt>Stack[AnyRef]</tt>. То есть, тип, присвоенный значению <tt>s</tt> — <tt>Stack[AnyRef]</tt>.
 
Помимо <tt>Nothing</tt>, который является подтипом всех других типов, есть также тип <tt>Null</tt>, являющийся подтипом <tt>scala.AnyRef</tt> и всех классов, наследующих от него. Литерал <tt>'''null'''</tt> в Scala — единственное значение этого типа, что делает этот литерал совместимым со всеми ссылочными типами, но не с типами значений, таких, как <tt>Int</tt>.
 
Мы завершим этот параграф полным улучшенным определением стеков. Теперь у них ковариантное подтипирование, метод <tt>push</tt> обобщен, и пустой стек представлен единственным объектом.
<font size=3><syntaxhighlight lang=Scala>
abstract class Stack[+A] {
def push[B >: A](x: B): Stack[B] = new NonEmptyStack(x, this)
def isEmpty: Boolean
def top: A
def pop: Stack[A]
}
object EmptyStack extends Stack[Nothing] {
def isEmpty = true
def top = error("EmptyStack.top")
def pop = error("EmptyStack.pop")
}
class NonEmptyStack[+A](elem: A, rest: Stack[A]) extends Stack[A] {
def isEmpty = false
def top = elem
def pop = rest
}
</syntaxhighlight></font>
 
Многие классы в библиотеке Scala — обобщенные. Теперь мы представим два часто используемых семейства обобщенных классов, кортежи и функции. Обсуждение других часто используемых классов, списков, приведено в следующей главе.
 
== Кортежи ==
== Функции ==