scala-`::`和`+:`之间的区别是什么?

::具有2种方法,可以指定将元素添加到(不可变)列表的前面:

  • ::(实现List),和
  • ::(仅在List中定义)

::技术上具有更通用的类型签名-

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

-但忽略了隐式,根据doc消息,仅要求::List,则签名是等效的。

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

编辑

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

另请参阅:Scala列表串联,::: vs ++

Mechanical snail asked 2020-08-03T17:38:38Z
2个解决方案
36 votes

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

+:的来源:

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

The source of +::

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)
}

如您所见,对于+:792,这两种方法都做一个相同的事情(编译器将为::参数选择List.canBuildFrom)。

那么,使用哪种方法呢? 通常,人们会选择接口(+:)而不是实现(::),但由于List是功能语言中的一种通用数据结构,因此具有自己的方法,该方法被广泛使用。 List的工作方式建立了许多算法。 例如,您会发现很多方法将单个元素放在List之前,或者调用方便的2995381143580580705797或tail方法,因为所有这些操作都是2995381143580705705799。因此,如果在本地使用2995381143580705705800(在单个方法或类内部),则存在 选择2995381143580705705801特定的方法没问题。 但是,如果要在类之间进行通信,即要编写一些接口,则应选择更通用的2995381143580580705802接口。

kiritsuku answered 2020-08-03T17:40:09Z
11 votes

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

scala> Range(1,4).+:(0)
res7: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 2, 3)
Kim Stebel answered 2020-08-03T17:40:29Z
translate from https://stackoverflow.com:/questions/11814675/whats-the-difference-between-and-for-prepending-to-a-list