Оператор Scala '::', как он работает?

В Scala я могу создать caseclass, case class Foo(x:Int), а затем поместить его в список следующим образом:

List(Foo(42))

Теперь ничего странного. Для меня это странно. Оператор :: является функцией в списке, правильно? С любой функцией с одним аргументом в Scala я могу назвать ее с помощью нотации infix. Примером является 1 + 2 - это функция (+) для объекта Int. Класс Foo, который я только что определил, не имеет оператора ::, так как возможно следующее:

Foo(40) :: List(Foo(2))

В Scala 2.8 RC1, я получаю следующий вывод из интерактивного приглашения:

scala> case class Foo(x:Int)
defined class Foo

scala> Foo(40) :: List(Foo(2))
res2: List[Foo] = List(Foo(40), Foo(2))

Я могу продолжать и использовать его, но что объясняет?

Ответ 1

Из Spec:

6.12.3 Инфиксные операции Оператор инфикса может быть произвольным идентификатор. Операторы Infix имеют приоритет и ассоциативность следующим образом.

...

Ассоциативность оператора определяемые операторами персонаж. Операторы, заканчивающиеся на двоеточие ': Являются право-ассоциативными. Все остальные операторы левоассоциативны.

Вы всегда можете увидеть, как эти правила применяются в Scala, путем печати программы после того, как она прошла через фазу "typer" компилятора:

scala -Xprint:typer -e "1 :: Nil"

val r: List[Int] = {
  <synthetic> val x$1: Int = 1;
  immutable.this.Nil.::[Int](x$1)
};

Ответ 2

Он заканчивается на :. И это знак того, что эта функция определена в классе справа (в классе List здесь).

Итак, это List(Foo(2)).::(Foo(40)), а не Foo(40).::(List(Foo(2))) в вашем примере.

Ответ 3

Один из аспектов, отсутствующих в ответах, заключается в том, что для поддержки :: в выражениях соответствия шаблону:

List(1,2) match {
  case x :: xs => println(x + " " + xs)
  case _ => println("")
}

Определен класс:::

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

поэтому case ::(x,xs) даст тот же результат. Выражение case x :: xs работает, потому что для класса case задан экстрактор по умолчанию :: и его можно использовать infix.

Ответ 4

Класс Foo, который я только что определил, не имеют оператор ::, так как возможно следующее:

Foo(40) :: List(Foo(2))

Если имя метода заканчивается двоеточием (:), метод вызывается в правом операнде, что здесь и происходит. Если имя метода не заканчивается двоеточием, метод вызывается в левом операнде. Например, a + b, + вызывается на a.

Итак, в вашем примере :: - это метод в его правом операнде, который является List.