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