Почему реализована реализация списка scala с именем:: и не имя класса? Есть ли какое-то особое значение?
Почему класс scala list named::
Ответ 1
Это будет работать с сопоставлением с образцом. У вас есть что-то, называемое шаблонами операторов Infix, где шаблон p op q
эквивалентен шаблону конструктора или экстрактора op(p, q)
.
Таким образом, класс case ::
определяет конструктор ::(head, tail)
. Это позволяет вам выполнить следующие действия:
list match {
case ::(head, tail) =>
}
Но с шаблоном оператора infix вы можете написать более знакомый синтаксис:
list match {
case head :: tail =>
}
Обратите внимание, что поиск stackoverflow в "[ scala] шаблоне инфикс-оператора" возвращает похожие вопросы и дополнительные примеры использования шаблона.
Ответ 2
Связанный список состоит из двух случаев: ячейки cons (с головой и хвостом) и пустого списка. Эти случаи называются ::
и Nil
соответственно в Scala, как на других языках с наследием ML. В неизменной реализации наиболее естественная кодировка выглядит примерно так:
sealed trait List[+A]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
case object Nil extends List[Nothing]
Это работает отлично, и в этом нет ничего плохого. Вы можете определить метод ::
на List
(или prepend
, если хотите), и все будет работать точно так, как вы ожидали. В этом случае "конкретная реализация" List
будет Cons
, хотя технически оба Cons
и Nil
являются конкретными реализациями.
Здесь проблема: мы хотим иметь возможность сопоставить шаблон по экземпляру List
, чтобы вернуть содержимое. Как бы то ни было, для соответствия шаблонов потребуется следующий синтаксис:
def sum(xs: List[Int]): Int = xs match {
case Cons(hd, tl) => hd + sum(tl)
case Nil => 0
}
Это немного уродливо. Нам действительно нужно иметь возможность использовать оператор ::
в нашем шаблоне так же, как мы его используем при построении списка изначально. Вот почему класс Cons
имеет имя ::
.
Определив класс case из двух параметров, мы в основном говорим Scala, что хотим, чтобы он позволил нам использовать этот класс case в качестве экстрактора инфикс в сопоставлении с образцом. Задний двоеточие делает этот экстрактор прав-ассоциативным, давая нам ожидаемый синтаксис:
sealed trait List[+A]
case class ::[+A](head: A, tail: List[A]) extends List[A]
case object Nil extends List[Nothing]
def sum(xs: List[Int]): Int = xs match {
case hd :: tl => hd + sum(tl)
case Nil => 0
}
Вот почему любой экземпляр List
с содержимым будет экземпляром класса ::
, так как это непустая реализация List
.
Ответ 3
Это стандартное имя оператора cons, который добавляет элемент в список.