Scala list concatenation,::: vs ++

时间:2011-07-02 22:43:02

标签: list scala concatenation

对于在Scala中连接列表,:::++之间是否有任何区别?

scala> List(1,2,3) ++ List(4,5)
res0: List[Int] = List(1, 2, 3, 4, 5)

scala> List(1,2,3) ::: List(4,5)
res1: List[Int] = List(1, 2, 3, 4, 5)

scala> res0 == res1
res2: Boolean = true

来自the documentation看起来++更为一般,:::List - 具体。提供后者是因为它用于其他功能语言吗?

4 个答案:

答案 0 :(得分:297)

旧。列表最初被定义为功能语言:

1 :: 2 :: Nil // a list
list1 ::: list2  // concatenation of two lists

list match {
  case head :: tail => "non-empty"
  case Nil          => "empty"
}

当然,Scala以临时方式演变了其他馆藏。当2.8出来时,系列经过重新设计,以实现最大程度的代码重用和一致的API,因此您可以使用++连接任何两个集合 - 甚至是迭代器。然而,List除了一两个被弃用之外,还要保留其原始运算符。

答案 1 :(得分:80)

:::仅适用于列表,而++可以与任何可遍历使用。在当前的实现(2.9.0)中,如果参数也是++,则:::会返回List

答案 2 :(得分:72)

始终使用:::。有两个原因:效率和类型安全。

<强>效率

x ::: y ::: zx ++ y ++ z快,因为:::是正确的关联。 x ::: y ::: z被解析为x ::: (y ::: z),其算法速度比(x ::: y) ::: z快(后者需要O(| x |)更多步骤。)

类型安全

使用:::,您只能连接两个List。使用++,您可以将任何集合附加到List,这很糟糕:

scala> List(1, 2, 3) ++ "ab"
res0: List[AnyVal] = List(1, 2, 3, a, b)

++也很容易与+

混淆
scala> List(1, 2, 3) + "ab"
res1: String = List(1, 2, 3)ab

答案 3 :(得分:20)

另一点是第一句被解析为:

scala> List(1,2,3).++(List(4,5))
res0: List[Int] = List(1, 2, 3, 4, 5)

而第二个例子被解析为:

scala> List(4,5).:::(List(1,2,3))
res1: List[Int] = List(1, 2, 3, 4, 5)

因此,如果你使用宏,你应该小心。

此外,两个列表的++正在调用:::,但开销更大,因为它要求一个隐式值,以便从列表到列表构建一个构建器。但是微基准测试在这个意义上并没有证明是有用的,我想编译器会优化这些调用。

升温后的微观基准。

scala>def time(a: => Unit): Long = { val t = System.currentTimeMillis; a; System.currentTimeMillis - t}
scala>def average(a: () => Long) = (for(i<-1 to 100) yield a()).sum/100

scala>average (() => time { (List[Int]() /: (1 to 1000)) { case (l, e) => l ++ List(e) } })
res1: Long = 46
scala>average (() => time { (List[Int]() /: (1 to 1000)) { case (l, e) => l ::: List(e ) } })
res2: Long = 46

正如Daniel C. Sobrai所说,你可以使用++将任何集合的内容附加到列表中,而使用:::只能连接列表。