在列表前加上`::`和`+:`之间有什么区别?

Mec*_*ail 43 scala list operators cons prepend

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

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

+: 技术上有一个更通用的类型签名 -

def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That
def ::[B >: A](x: B): List[B]
Run Code Online (Sandbox Code Playgroud)

-丁忽略隐式的,它根据该文档信息仅需要ThatList[B],签名是等效的.

List.+:和之间有什么区别List.::如果它们实际上是相同的,我认为+:最好避免取决于具体实施List.但是为什么定义了另一个公共方法,客户端代码何时会调用它?

编辑

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

另请参阅:Scala list concatenation,::: vs ++

kir*_*uku 36

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

:::

def ::[B >: A] (x: B): List[B] =
  new scala.collection.immutable.::(x, this)
Run Code Online (Sandbox Code Playgroud)

+::

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)
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的那样List,两种方法都是一样的(编译器会为参数选择List.canBuildFromCanBuildFrom).

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

  • @Mechanicalsnail:Scala社区已经对`::`的意义进行了一些讨论.经常提到的另一点是`::`的存在有历史原因.Scala的第一个版本没有像我们今天这样的通用集合.此外,'ML`系列函数式语言确实有`:`作为List-prepending运算符.因此它的起源可能看起来更深. (3认同)

Kim*_*bel 11

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

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