В Scala я могу сделать caseclass, case class Foo(x:Int)
, и затем помещенный это в список как так:
List(Foo(42))
Теперь, ничто странное здесь. Следующее является странным для меня. Оператор ::
функция в списке, правильно? С любой функцией с одним аргументом в Scala я могу назвать его с инфиксной нотацией. Пример 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))
Я могу пойти и использовать его, но каково объяснение?
Из спецификации:
6.12.3 Инфиксные операции Инфиксный оператор может быть произвольным идентификатором. Инфиксные операторы имеют предшествование и ассоциативность, которые определяются следующим образом.
...
Ассоциативность оператора определяется последним символом. Операторы, заканчивающиеся двоеточием ':' являются право-ассоциативными. Все остальные операторы являются лево-ассоциативными.
Вы всегда можете увидеть, как эти правила применяются в Scala, распечатав программу после того, как она прошла через фазу 'typer' компилятора:
scala -Xprint:typer -e "1 :: Nil"
val r: List[Int] = {
<synthetic> val x$1: Int = 1;
immutable.this.Nil.::[Int](x$1)
};
Он заканчивается :
. И это признак того, что эта функция определена в классе справа (здесь в классе List
).
Итак, это List (Foo (2)) .: :( Foo (40))
, а не Foo (40) .: :( List (Foo (2)))
в вашем примере.
Класс
Foo
, который я только что определил, не имеет оператора::
, поэтому как возможно следующее:
Foo (40) :: List (Foo (2))
Если имя метода заканчивается двоеточием (:
), метод вызывается для правого операнда , который является случай здесь. Если имя метода не заканчивается двоеточием, метод вызывается для левого операнда. Например, a + b
, +
вызывается на a
.
Итак, в вашем примере ::
- это метод в правом операнде, который представляет собой список List
.
В приведенных ответах отсутствует один аспект: поддержка ::
в выражениях сопоставления с образцом:
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, и его можно использовать инфиксным.