为什么scala列表实现名为::而不是类名?那背后有一些特殊的含义吗?
答案 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
,但从技术上讲,Cons
和Nil
都是具体实现。
这是问题所在:我们希望能够在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运算符的标准名称。