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
函数式语言家族确实有:
作为列表前置运算符。因此,它的起源可能看起来要深得多。