2014-01-22 38 views
12

This SO answer描述如何scala.collection.breakOut可用来防止产生浪费的中间集合。例如,我们在这里建立一个中间Seq[(String,String)]scala.collection.breakOut VS视图

val m = List("A", "B", "C").map(x => x -> x).toMap 

通过使用breakOut我们可以防止这种中间Seq的创作:

val m: Map[String,String] = List("A", "B", "C").map(x => x -> x)(breakOut) 

Views solve the same problem,另外访问元素懒洋洋地:

val m = (List("A", "B", "C").view map (x => x -> x)).toMap 

我假设View包装的创作是相当便宜的,所以我的疑问句重刑是:是否有任何真正的理由使用breakOut而不是View

回答

11

我不认为viewsbreakOut是相同的。

breakOut是通过消除中间步骤,以简化变换操作的CanBuildFrom实现。例如,从A到B没有中间收集。 A breakOut意味着让Scala选择合适的构建器对象,以便在给定场景中生成新项目的最大效率。更多细节here

views处理不同类型的效率,主要销售音高是:“没有更多的新对象”。对象浏览商店光源参考,以解决不同的使用场景:懒惰接入等

底线:

如果map上一个view,你还可以得到创建引用的中介集合可产生预期的结果之前, 。你仍然可以有优越的性能来自:

collection.view.map(somefn)(breakOut) 

比:

collection.view.map(someFn) 
12

你会做从英国到法国旅行。

有了看法:你服用了一组音符在你的笔记本和繁荣,一旦你叫.force()你开始做所有的人:buy a ticket, board on the plane, ....

有了突破:你出发,繁荣,你在巴黎看着埃菲尔铁塔。你不记得你到达那里的确切程度,但你确实做过这次旅行,只是没有记忆。

糟糕的比喻,但我希望这给你一个他们之间有什么区别的味道。

1

什么弗拉维安说。

视图的一种用例是节省内存。举例来说,如果你有一百万个字符长的字符串original,并使用需要,一个接一个,所有的字符串亿个后缀的,可以使用的

val v = original.view 
val suffixes = v.tails 

意见收集原始串。然后你可以循环遍历后缀,使用suffix.force()将它们转换回循环内的字符串,因此一次只能在内存中保存一个。当然,你可以用你自己的循环遍历原始字符串的索引来做同样的事情,而不是创建任何形式的后缀集合。

另一个用例是创建派生对象昂贵时,您需要它们在一个集合中(比如说,作为地图中的值),但只能访问一些,而您不知道哪些。

如果你真的有在那里它们之间选择有意义的情况下,宁愿突破除非有使用视图(如上面的)一个很好的理由。

  • 查看需要更多的代码更改和关怀比突破,在您需要添加力()需要的地方。取决于上下文,不能这样做的是 通常只能在运行时检测到。有breakout,一般如果它编译 ,这是正确的。
  • 在视图不适用的情况下,breakOut 将会更快,因为视图生成和强制会被跳过。
  • 如果您使用调试器,则可以检查收集内容,而您对某个视图集合无法做到这一点。