Ответ 1
Это класс и . Минусы - это тип параметризованного класса. Список [A] имеет два подкласса: Cons и Nil. Поскольку Cons является классом, он может быть создан его конструктором следующим образом:
val s = new ::[Int](4, Nil)
Концы - это класс case, и мы используем конструктор, когда мы выполняем сопоставление шаблонов. Минусы также являются методом класса list, который реализуется в двух его подклассах. Следовательно, мы можем использовать метод cons для класса cons, который мы создали выше.
val s1 = s.::(5)
Может возникнуть путаница, потому что мы обычно создаем списки, используя метод apply объекта List:
val s2 = List(1, 2, 3)
Обычно метод apply объекта возвращает новый экземпляр класса с тем же именем, что и объект. Это, однако, просто конвенция. В этом конкретном случае объект List возвращает новый экземпляр подкласса Cons. Сам класс List является закрытым абстрактным классом, поэтому его нельзя создать. Таким образом, применяемый выше метод выполняет следующие действия:
val s2 = 1 :: 2 :: 3 :: Nil
Любой метод, который заканчивается на ":", - это метод в операнде справа, поэтому его можно переписать как
val s2 = 1 :: (2 :: (3 :: Nil)) //or as
val s2 = Nil.::(3).::(2).::(1)
Таким образом, метод Cons (::) на объекте Nil принимает значение 3 в качестве параметра и создает анонимную копию класса Cons с 3 в качестве главы и ссылкой на объект Nil как его хвост. Позволяет называть этот анонимный объект c1. Затем метод Cons затем вызывается на c1, принимающем 2 в качестве параметра, возвращающего новый анонимный экземпляр Cons, позволяет называть его c2, у которого есть 2 для его головы и ссылка на c1 как его хвост. Затем, наконец, метод cons на объекте c2 принимает значение 1 в качестве параметра и возвращает названный объект s2 с 1 в качестве главы и ссылкой на c2 в качестве его хвоста.
Вторая точка путаницы заключается в том, что таблицы REPL и Scala используют методы класса toString для отображения результатов. Итак, рабочий лист дает нам:
val s3 = List(5, 6, 7) // s3 : List[Int] = List(5, 6, 7)
val s4 = List() // s4 : List[Nothing] = List()
val s5: List[Int] = List() // s5 : List[Int] = List()
s3.getClass.getName // res3: String = scala.collection.immutable.$colon$colon
s4.getClass.getName // res4: String = scala.collection.immutable.Nil$
s5.getClass.getName // res5: String = scala.collection.immutable.Nil$
Как сказано выше, список закрыт, поэтому новые подэлементы не могут быть созданы, поскольку Nil является объектом, а Cons - окончательным. Поскольку Nil является объектом, он не может быть параметризован. Ниль наследует от List [Nothing]. На первый взгляд это не звучит так полезно, но помните, что эти структуры данных неизменяемы, поэтому мы никогда не можем добавлять их напрямую, а Nothing - подкласс каждого класса. Таким образом, мы можем добавить класс Nil (косвенно) в любой Список без проблем. В классе Cons есть два члена - голова и другой список. Это довольно аккуратное решение, когда вы его часы.
Я не уверен, что это практическое применение, но вы можете использовать Cons как тип:
var list: ::[Int] = List (1,2,3).asInstanceOf[::[Int]]
println("Initialised List")
val list1 = Nil
list = list1.asInstanceOf[::[Int]] //this will throw a java class cast exception at run time
println("Reset List")