Scala的'::'运算符,它是如何工作的?

Fel*_*lix 54 scala list operator-keyword

在Scala中,我可以创建一个caseclass,case class Foo(x:Int)然后将它放在一个列表中,如下所示:

List(Foo(42))
Run Code Online (Sandbox Code Playgroud)

现在,这里没什么奇怪的.以下对我来说很奇怪.运算符::是列表中的函数,对吧?对于Scala中有一个参数的任何函数,我可以用中缀表示法调用它.一个例子是对象的1 + 2一个函数.我刚刚定义的类没有运算符,那么以下可能如何?(+)IntFoo::

Foo(40) :: List(Foo(2))
Run Code Online (Sandbox Code Playgroud)

在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))
Run Code Online (Sandbox Code Playgroud)

我可以继续使用它,但解释是什么?

ret*_*nym 49

来自规格:

6.12.3 Infix操作中缀操作符可以是任意标识符.中缀运算符的优先级和关联性定义如下.

...

操作员的关联性由操作员的最后一个字符决定.以冒号':'结尾的运算符是右关联的.所有其他运算符都是左关联的.

通过在编译器的"typer"阶段之后打印程序,您始终可以看到如何在Scala中应用这些规则:

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

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


fol*_*one 22

它结束了:.这就是标志,这个函数是在右边的类中定义的(在List这里的类中).

所以,这List(Foo(2)).::(Foo(40))不是Foo(40).::(List(Foo(2)))你的例子.

  • 换句话说,`a ::::: b`(只是愚蠢)与`b.:::: :( a)`相同.此外,方法的名字结束结肠和中缀风格关联使用的权利,而不是左,所以'A :: B :: C`是一样的`c.::(b.::(a )))` (4认同)

Tho*_*ung 18

给出的答案中缺少的一个方面是支持::模式匹配表达式:

List(1,2) match {
  case x :: xs => println(x + " " + xs)
  case _ => println("")
}
Run Code Online (Sandbox Code Playgroud)

类::定义:

final case class ::[B](private var hd: B, private[scala] var tl: List[B]) 
Run Code Online (Sandbox Code Playgroud)

所以case ::(x,xs)会产生相同的结果.该表达式case x :: xs有效,因为::为case类定义了默认提取器,并且可以使用中缀.


Sur*_*apu 16

Foo我刚刚定义的类没有::运算符,所以如何可能:

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

如果方法名以冒号(:)结尾,则在右操作数上调用该方法,这是这里的情况.如果方法名称不以冒号结尾,则在左操作数上调用该方法.例如,a + b,+被调用上a.

所以,在你的例子中,::是一个右边操作数的方法,它是一个List.