Scala и объект :: - PullRequest
       19

Scala и объект ::

6 голосов
/ 15 марта 2011

Я нырял в скалу, и до сих пор мне это очень нравится. Я перехожу к сопоставлению с образцом и кейсам, и следующее несколько озадачило меня. Я знаю, что он делает, но я хочу точно понять, что происходит

var list = List(2,3,4)
1::list

Если я до сих пор прав в своем понимании. Тогда :: представляет объект case. Если так, то мой вопрос:

как я "оставил заявку" на 1? вместо того, чтобы :: быть методом 1. По сути, кто-то может несколько отделить это утверждение 1 :: list, показывая, что на самом деле происходит (т.е. какие методы вызываются для какого объекта)

Спасибо

Ответы [ 5 ]

18 голосов
/ 15 марта 2011

Раздражает, что некоторые из наиболее заметных и удивительных особенностей Scala имеют такую ​​сложность прямо под поверхностью. Итак, рассмотрим эту простую строку:

val (head :: tail): ::[Int] = 1 :: Nil

Каждое из трех мест, где появляется ::, относится к другому :: и другому механизму в Scala. Давайте рассмотрим каждый из них по порядку.

head :: tail

То, что здесь происходит, это сопоставление с шаблоном , точно так же, как можно увидеть с помощью case операторов. Сопоставление с образцом может появляться в val назначениях, в левой части <- в for пониманиях и в case утверждениях.

Итак, как происходит это конкретное сопоставление с образцом? Что ж, всякий раз, когда шаблон имеет формат a b c, Scala переводит его в b(a, c), который затем переводится в вызовы unapply или unapplySeq для объекта b.

Итак, :: в val (head :: tail) относится к объекту :: (определенному через case class).

: ::[Int]

Это объявление типа, поэтому ::[Int] это тип. :: сам по себе является классом, а также конструктором типов (поскольку он создает типы по заданному параметру типа - ::[Int] - это один тип, ::[String] - другой тип и т. Д.). Это также подкласс List, который имеет только два подкласса: :: и класс синглтона Nil.

Это объявление излишне, и, вообще говоря, вряд ли когда-либо будет использоваться :: в качестве типа или класса. Я показываю это здесь в основном для полноты.

1 :: Nil

Здесь :: - это метод. Это метод List, поэтому, поскольку Nil является List, а 1 - нет, он должен принадлежать Nil (или быть доступным через неявное преобразование).

Следует отметить, что методы, заканчивающиеся на :, при использовании в нотации инфиксного оператора связываются справа, а не слева. Или, другими словами, a :: b эквивалентно b.::(a).

Этот механизм используется редко и, я подозреваю, в основном сделан для того, чтобы сделать традиционные алгоритмы списка fp более знакомыми программистам, использующим fp. Он используется в некоторых других местах стандартной библиотеки Scala и вне ее.

Например, в Scala 2.8 теперь есть +:, который служит для той же цели, что и ::, но определен для всех Seq. Он отражается :+, который добавляет элементы, и чей : не служит никакой другой цели, кроме устранения неоднозначности его с +, который перегружен для объединения строк.

10 голосов
/ 15 марта 2011

Имя оператора, оканчивающееся на :, связывается справа. :: [A] на самом деле case class и подкласс List[A], как видно из справки по Scala API . :: также является методом, работающим со своим правым аргументом, списком, принимающим левый операнд в качестве аргумента и возвращающим ::[A].

Итак, в вашем примере метод :: вызывается для list с 1 в качестве аргумента. Это создает объект типа :: [Int] с аргументами 1 и list.

7 голосов
/ 15 марта 2011

Очень быстрый ответ.Метод :: вызывается в списке с параметром 1.

Любое имя метода (и да, :: это метод), заканчивающееся двоеточием, работает с правым операндом.

1 голос
/ 15 марта 2011

Я понимаю, что :: (оператор "cons") таков, что он используется таким образом, потому что добавление элемента в список (технически, создание нового списка с новым элементом, добавленным к старому списку) имеет значение O(1), в то время как добавление было бы O (N).Это вещь эффективности ...

1 голос
/ 15 марта 2011

Чтобы добавить дополнительную информацию к другим ответам:

:: является подклассом List

final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extends List[B] { ... }

и метод на List

def ::[B >: A] (x: B): List[B] = new scala.collection.immutable.::(x, this)

, который в основном реализован в терминах первого.

Так что за этим нет глубоких теоретических основ, просто имейте в виду правило о методах, заканчивающихся на :.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...