List
有两个方法,它们被指定为将元素前置到(不可变)列表:
+:
(实现Seq.+:
),以及::
(仅在List
中定义)
+:
在技术上有一个更通用的类型签名——
def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That
def ::[B >: A](x: B): List[B]
--但忽略隐式,根据doc消息,隐式仅要求That
为List[B]
,签名是等效的。
List.+:
和List.::
之间有什么区别如果它们实际上是相同的,我认为+:
最好避免,这取决于具体的实现List
。但是,为什么要定义另一个公共方法,客户端代码什么时候会调用它呢?
编辑
模式匹配中还有一个::
的提取器,但我想知道这些特定的方法。
另请参阅:Scala列表串联,::vs++
确定两种方法之间差异的最佳方法是查看源代码。
::
的来源:
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.canBuildFrom)。
那么,该使用哪种方法呢?通常,人们会选择接口(+:
)而不是实现(::
),但由于List
是函数语言中的通用数据结构,它有自己的方法,这些方法被广泛使用。许多算法都是以CCD_ 21的工作方式构建的。例如,您会发现许多方法将单个元素前置到List
,或者调用方便的head
或tail
方法,因为所有这些操作都是O(1)
。因此,如果您在本地使用List
(在单个方法或类内部),那么选择List
特定的方法是没有问题的。但是,如果你想在类之间进行通信,即你想编写一些接口,你应该选择更通用的Seq
接口。
+:
更通用,因为它允许结果类型与调用对象的类型不同。例如:
scala> Range(1,4).+:(0)
res7: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 2, 3)