List 什么';“::”和“+;:”之间的区别是什么用于列表的前置)?

List 什么';“::”和“+;:”之间的区别是什么用于列表的前置)?,list,scala,operators,prepend,cons,List,Scala,Operators,Prepend,Cons,List有两种方法指定用于将元素前置到(不可变)列表: +:(实现序列+:),以及 :(仅在列表中定义) +:技术上有一个更通用的类型签名- def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That def ::[B >: A](x: B): List[B] -但是忽略隐式签名,根据doc消息,隐式签名仅要求为List[B],签名是等效的 列表+:和列表之间的区别是什么?如果

List
有两种方法指定用于将元素前置到(不可变)列表:

  • +:
    (实现
    序列+:
    ),以及
  • (仅在
    列表中定义)
+:
技术上有一个更通用的类型签名-

def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That
def ::[B >: A](x: B): List[B]
-但是忽略隐式签名,根据doc消息,隐式签名仅要求
List[B]
,签名是等效的

列表+:
和列表之间的区别是什么?如果它们事实上是相同的,我假设
+:
最好避免依赖具体的实现
列表
。但为什么定义了另一个公共方法,客户机代码何时调用它

编辑 模式匹配中还有一个用于
的提取器,但我想知道这些特殊的方法


另请参见:

确定两种方法之间差异的最佳方法是查看源代码

def ::[B >: A] (x: B): List[B] =
  new scala.collection.immutable.::(x, this)
+:

override def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That = bf match {
  case _: List.GenericCanBuildFrom[_] => (elem :: this).asInstanceOf[That]
  case _ => super.+:(elem)(bf)
}
如您所见,对于
List
,两种方法都执行相同的操作(编译器将为
CanBuildFrom
参数选择)


那么,使用哪种方法呢?通常,人们会选择接口(
+:
)而不是实现(
),但由于
列表
是函数式语言中的通用数据结构,因此它有自己广泛使用的方法。许多算法建立在
List
的工作方式上。例如,您会发现许多方法将单个元素预先添加到
List
或调用方便的
head
tail
方法,因为所有这些操作都是
O(1)
。因此,如果您在本地使用
列表
(在单个方法或类内部),那么选择特定于
列表的方法是没有问题的。但是,如果您想在类之间通信,也就是说,您想编写一些接口,那么您应该选择更通用的
Seq
接口。

+:
更通用,因为它允许结果类型与调用它的对象的类型不同。例如:

scala> Range(1,4).+:(0)
res7: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 2, 3)

但是为什么他们公开了
List.:
?看起来他们本可以实现
列表中的所有内容。+:
,用
新的scala.collection.immutable.:(elem,this)替换第一个
案例中对
的调用
@Mechanicalsnail我认为这样做是为了使算法显然依赖于
列表
,而不是一般的
序列
,原因已经由sschaef解释过了。此外,根据统计,每个
Seq
实现的使用方式存在巨大差异。例如,
+:
将在
队列
上执行异常,使用
可以防止您意外地将其传递给算法。@Mechanicalsnail:Scala社区已经就
的含义进行了一些讨论。经常提到的另一点是,
的存在有历史原因。Scala的第一个版本没有像今天这样的通用集合。此外,
ML
函数式语言家族确实有
作为列表前置运算符。因此,它的起源可能看起来要深得多。