2010-05-13 25 views
39

在Scala中,我可以做一个caseclass,case class Foo(x:Int),然后把它放在一个列表,像这样:斯卡拉的'::'运算符,它是如何工作的?

List(Foo(42)) 

现在,任何异常。以下对我来说很陌生。运营商::是一个列表上的功能,对吗?使用Scala中的一个参数的任何函数,我都可以用中缀表示法来调用它。 一个示例是1 + 2是对象Int上的函数(+)。我刚刚定义的类Foo没有::运算符,那么以下情况可能如何?

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

在斯卡拉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)) 

我可以继续使用它,但究竟是如何解释呢?

回答

39

从规格:

6.12.3 InfixOperations中缀运算符可以是任意 标识符。 Infix操作符具有 优先级和相关性定义如下 。

...

操作的关联性是 通过运营商的最后一个字符 确定。以冒号 ':'结尾的运算符是右结合的。所有其他 运营商都是左联合的。

你总是可以看到打印的程序也已通过编译器的“打字员”阶段之后,这些规则是如何在斯卡拉应用:

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

val r: List[Int] = { 
    <synthetic> val x$1: Int = 1; 
    immutable.this.Nil.::[Int](x$1) 
}; 
+1

它也适用于将类型参数传递给类型构造函数。假设你有一个case class :: [H,T](head:H,tail:T);和类SomeType [A];那么你可以做新的SomeType [:: [String,Int]](“a”,3)和新的SomeType [H :: T](“a”,3) – lisak 2014-08-04 13:45:43

19

它以:结尾。这就是符号,这个函数是在右边的类中定义的(在这里的List这个类中)。

因此,它的List(Foo(2)).::(Foo(40)),而不是Foo(40).::(List(Foo(2)))在你的例子。

+4

换句话说,'a ::::: b'(就是愚蠢)和'b :: ::: :(a)'是一样的。另外,名称以冒号结尾并用于中缀风格的方法与右侧相关,而不是左侧,因此'a :: b :: c'与'c.::(b.::(a )))' – 2010-05-13 14:03:43

12

Foo我刚才定义不 有::运营商,所以如何是 以下可能:

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

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

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

15

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

List(1,2) match { 
    case x :: xs => println(x + " " + xs) 
    case _ => println("") 
} 

A class :: is defined

final case class ::[B](private var hd: B, private[scala] var tl: List[B]) 

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