59

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

List(Foo(42))

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

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

4 回答 4

54

从规范:

6.12.3 中缀操作 中缀运算符可以是任意标识符。中缀运算符具有如下定义的优先级和结合性。

...

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

在程序经过编译器的“打字机”阶段后,您总是可以通过打印程序来查看这些规则是如何在 Scala 中应用的:

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

val r: List[Int] = {
  <synthetic> val x$1: Int = 1;
  immutable.this.Nil.::[Int](x$1)
};
于 2010-05-13T14:10:59.553 回答
24

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

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

于 2010-05-13T14:01:12.007 回答
20

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

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有效,因为默认提取器::是为案例类定义的,并且可以使用中缀。

于 2010-05-18T11:54:47.173 回答
19

我刚刚定义的类Foo没有::运算符,那么以下怎么可能:

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

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

因此,在您的示例中,::它的右操作数是一个方法,它是List.

于 2010-05-13T14:26:52.043 回答