Scala list concatenation,::: vs ++

用于连接在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 

从文档看起来像++更一般,而:::List特定的。 是否提供了后者,因为它在其他function语言中使用?

遗产。 列表最初被定义为function语言:

 1 :: 2 :: Nil // a list list1 ::: list2 // concatenation of two lists list match { case head :: tail => "non-empty" case Nil => "empty" } 

当然,斯卡拉以特别的方式演变了其他collections。 当2.8出来的时候,集合被重新devise,以实现最大的代码重用和一致的API,所以你可以使用++连接任何两个集合,甚至迭代器。 但是,List只能保留原来的运营商,除了一两个已经废弃的运营商。

:::只能和列表一起工作,而++可以和任何可穿越的一起使用。 在当前实现(2.9.0)中,如果参数也是一个List ,则++会回退:::

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

效率

x ::: y ::: zx ++ y ++ z快,因为:::是正确的关联。 x ::: y ::: z被parsing为x ::: (y ::: z) ,这在algorithm上比(x ::: y) ::: z更快(后者需要O(| x |)更多步骤)。

types安全

使用:::只能连接两个List 。 用++你可以追加任何collections到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 

不同的一点是,第一句被parsing为:

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

而第二个例子被parsing为:

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

所以如果你使用macros,你应该保重。

此外,两个列表的++是调用:::但有更多的开销,因为它要求一个隐式的值有一个生成器从列表到列表。 但是microbenchmarks在这个意义上没有certificate任何有用的东西,我想编译器会优化这样的调用。

微型基准热身后。

 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所说,你可以使用++将任何集合的内容追加到列表中,而对于:::只能连接列表。