斯卡拉的“::”运算符,它是如何工作的?
在Scala中,我可以创buildcaseclass, case class Foo(x:Int)
,然后将它放在如下所示的列表中:
List(Foo(42))
现在,这里没什么奇怪的。 以下对我来说很陌生。 operator ::
是一个列表上的函数,对吗? 在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中缀操作中缀操作符可以是任意的标识符。 中缀运算符的优先级和关联性定义如下。
…
运算符的关联性由运算符的最后一个字符决定。 以冒号“:”结尾的操作符是右关联的。 所有其他运营商都是左联合的。
您可以随时通过在编译器的“typer”阶段之后打印程序来了解Scala如何应用这些规则:
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)))
。
给出的答案中缺less的一个方面是在模式匹配expression式中支持::
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)
会产生相同的结果。 expression式case x :: xs
工作原理是因为默认的提取器::
是为case类定义的,它可以用于中缀。
我刚刚定义的类
Foo
没有::
运算符,那么以下可能如何:
Foo(40) :: List(Foo(2))
如果方法名以冒号(:)结尾,则在右边的操作数上调用方法,在这里就是这种情况。 如果方法名称不以冒号结尾,则在左操作数上调用该方法。 例如, a + b
上调用a + b
, +
。
所以,在你的例子中, ::
是右边操作数的一个方法,它是一个List
。