48

List有 2 种方法指定将元素添加到(不可变)列表中:

  • +:(实施Seq.+:),和
  • ::(仅在 中定义List

+:技术上具有更通用的类型签名——</p>

def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That
def ::[B >: A](x: B): List[B]

——但忽略隐含的,根据文档消息只需要Thatbe List[B],签名是等价的。

List.+:和 和有什么不一样List.::如果它们实际上是相同的,我认为+:最好避免取决于具体的实现List。但是为什么要定义另一个公共方法,客户端代码什么时候会调用它呢?

编辑

还有一个用于::模式匹配的提取器,但我想知道这些特定的方法。

另请参阅:Scala 列表连接,::: vs ++

4

2 回答 2

41

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

来源:::_ _

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,这两种方法都是一样的(编译器将选择List.canBuildFrom作为CanBuildFrom参数)。

那么,使用哪种方法呢?通常人们会选择接口(+:)而不是实现(::),但是因为List它是函数式语言中的一种通用数据结构,它有自己的被广泛使用的方法。许多算法都是按照工作方式构建的List。例如,您会发现很多方法将单个元素添加到List或调用方便的headortail方法,因为所有这些操作都是O(1). 因此,如果您在本地使用 a List(在单个方法或类内部),则选择List-specific 方法没有问题。但是如果你想类之间进行通信,即你想写一些接口,你应该选择更通用的Seq接口。

于 2012-08-05T07:40:57.463 回答
14

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

scala> Range(1,4).+:(0)
res7: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 2, 3)
于 2012-08-05T07:43:57.983 回答