Оператор Scala'::', как он работает?
В 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))
Я могу продолжать и использовать это, но каково объяснение?
4 ответа
Из спецификации:
6.12.3 Операции Infix Оператор 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)
};
Заканчивается :
, И это признак того, что эта функция определена в классе справа (в List
класс здесь).
Так что это List(Foo(2)).::(Foo(40))
не Foo(40).::(List(Foo(2)))
в вашем примере.
Один из аспектов, отсутствующий в данных ответах, заключается в том, что ::
в выражениях сопоставления с образцом:
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.
Класс
Foo
Я только что определил, не имеет::
оператор, так как это возможно:
Foo(40) :: List(Foo(2))
Если имя метода заканчивается двоеточием (:
) метод вызывается для правого операнда, который здесь имеет место. Если имя метода не заканчивается двоеточием, метод вызывается в левом операнде. Например, a + b
, +
вызывается на a
,
Итак, в вашем примере, ::
метод на своем правом операнде, который является List
,