Оператор 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
.