为什么scala列表类名为::

时间:2011-10-06 04:57:12

标签: list scala

为什么scala列表实现名为::而不是类名?那背后有一些特殊的含义吗?

3 个答案:

答案 0 :(得分:22)

链表由两种情况组成:cons单元(带头部和尾部)和空列表。这些案例在Scala中分别称为::Nil,与其他具有ML遗产的语言一样。在不可变的实现中,最自然的编码看起来像这样:

sealed trait List[+A]

case class Cons[+A](head: A, tail: List[A]) extends List[A]
case object Nil extends List[Nothing]

这很好用,它确实没什么问题。您可以在::(或List,如果您愿意)定义prepend方法,并且事情的工作方式完全符合您的预期。在这种情况下,List的“具体实现”将为Cons,但从技术上讲,ConsNil都是具体实现。

这是问题所在:我们希望能够在List的实例上进行模式匹配以获取内容。事实上,模式匹配需要以下语法:

def sum(xs: List[Int]): Int = xs match {
  case Cons(hd, tl) => hd + sum(tl)
  case Nil => 0
}

虽然这有点难看。我们真正想要的是能够在我们的模式匹配中使用::运算符,就像我们在最初构造列表时使用它一样。这就是Cons类名为::

的原因

通过定义两个参数的case类,我们基本上告诉Scala我们希望它允许我们在模式匹配中使用该case类作为中缀提取器。尾部冒号使该提取器成为右关联的,为我们提供了预期的语法:

sealed trait List[+A]

case class ::[+A](head: A, tail: List[A]) extends List[A]
case object Nil extends List[Nothing]

def sum(xs: List[Int]): Int = xs match {
  case hd :: tl => hd + sum(tl)
  case Nil => 0
}

这就是为什么任何具有内容的List实例都将成为类::的实例,因为这是List的非空实现。

答案 1 :(得分:21)

这适用于模式匹配。你有一个叫做中缀运算符模式的东西,其中模式p op q等同于构造函数或提取器模式op(p, q)

因此案例类::定义了构造函数::(head, tail)。这允许你像这样匹配:

list match {
  case ::(head, tail) =>
}

但是使用中缀运算符模式,您可以编写更熟悉的语法:

list match {
  case head :: tail =>
}

请注意,"[scala] infix operator pattern"上的stackoverflow搜索会返回类似的问题以及该模式的其他用例。

答案 2 :(得分:3)

这是将元素添加到列表中的cons运算符的标准名称。