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

Posted

技术标签:

【中文标题】Scala 的 \'::\' 运算符,它是如何工作的?【英文标题】:Scala's '::' operator, how does it work?Scala 的 '::' 运算符,它是如何工作的? 【发布时间】:2011-02-19 02:46:42 【问题描述】:

在 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))

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

【问题讨论】:

【参考方案1】:

来自规范:

6.12.3 InfixOperations 中缀运算符可以是任意的 标识符。中缀运算符有 定义的优先级和关联性 如下。

...

运算符的结合性是 由运营商的最后决定 特点。以冒号结尾的运算符 ‘:’ 是右结合的。所有其他 运算符是左结合的。

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

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

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

【讨论】:

它也适用于将类型参数传递给类型构造函数。假设您有一个案例类 ::[H, T](head : H, tail : T);和类 SomeType[A];那么你可以同时做 new SomeType[::[String, Int]]("a", 3) 和 new SomeType[H :: T]("a", 3)【参考方案2】:

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

所以,在您的示例中是List(Foo(2)).::(Foo(40)),而不是Foo(40).::(List(Foo(2)))

【讨论】:

换句话说,a ::::: b(只是为了傻)与b.:::::(a)相同。此外,名称以冒号结尾并用于中缀样式的方法关联到右侧而不是左侧,因此a :: b :: cc.::(b.::(a))) 相同【参考方案3】:

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

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

【讨论】:

【参考方案4】:

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

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

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

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

【讨论】:

以上是关于Scala 的 '::' 运算符,它是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

Scala 中的递增 (++) 运算符

FOR循环中的逗号运算符,它是如何工作的?

SQL“或”运算符。在以下场景中它是如何工作的?

使用 Scala 解析器的运算符关联性

在 Ruby 中,“=>”是啥意思,它是如何工作的? [复制]

递归集合并集:它是如何工作的?