为什么scala的收藏品不是'观点'默认情况下?

时间:2015-07-06 20:23:50

标签: scala collections

在某些情况下,应用'查看'在进行map / filter / ...之前收集可以降低性能。但是,这些情况很少(afaik),例如,当只有一次操作时。

但大部分时间都附加了' .view'通过阻止创建中间集合,可以提高性能。

那么,为什么要观看'默认情况下不适用于集合?我错过了一些隐藏的费用吗?

1 个答案:

答案 0 :(得分:8)

简短回答:视图并不总是有益的,默认情况下严格的行为可以防止出现意外。

考虑早期collections documentation的这个代码段:

  

...你可能想知道为什么要有严格的收藏品?一个原因是性能比较并不总是偏向于严格的集合。对于较小的集合大小,在视图中形成和应用闭包的额外开销通常大于避免中间数据结构的收益。

考虑:

List(1, 2).map(_ + 1)
// vs
List(1, 2).view.map(_ + 1) 

view仅使用更多的开销,并且一些粗略的测量结果慢了约4%(一小部分,但明显不同)。

文件继续说:

  

一个可能更重要的原因是,如果延迟操作有副作用,视图中的评估会非常混乱。

考虑:

for(i <- (1 to 10)) println(i)

如果(1 to 10)实际上是view(事实并非如此),那么在被迫这样做之前不会发生任何事情。直截了当的代码可能不是。

更糟糕的是,您可能会遇到令人惊讶的情况,最终您需要重新评估您不需要的代码。拿这个天真的例子:

// Evaluates to List(2, 3, 4, 5), prints "eval" during each evaluation
val list = List(1, 2, 3, 4).view.map { i => println("eval"); i + 1 }

// For each element in the list, prints the elements that *not* that element (in a view)
def printList[A](list: Traversable[A]): Unit = 
    list foreach { i => list.filter(_ != i) }

由于listviewprintList评估list n - 1 的次数超过了应有的数量!

scala> printList(list)
eval
SeqViewMF(...)
eval
SeqViewMF(...)
eval
SeqViewMF(...)
eval
SeqViewMF(...)

现在假设list未明确标记为view(默认情况下为视图)。我可以想象出因意外的重新评估而发生的许多奇怪的错误或瓶颈。

这并不是说严格的评估不会带来它自己的惊喜。这只是一种设计选择,严格评估不如懒惰评估那么令人惊讶(Paul Phillips可能不同意)。