scala.collection.breakOut vs views

时间:2014-01-22 14:27:20

标签: scala scala-collections

This SO answer描述了如何使用scala.collection.breakOut来防止创建浪费的中间集合。例如,我们在这里创建一个中间Seq[(String,String)]

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

4 个答案:

答案 0 :(得分:14)

你打算从英国到法国旅行。

有了观点:你在你的笔记本和繁荣中拿了一套笔记,一旦你打电话给.force(),你就开始制作所有笔记:buy a ticket, board on the plane, ....

随着breakOut:你正在离开和繁荣,你在巴黎看着埃菲尔铁塔。你不记得你到底是怎么到达那里的,但实际上你做过这次旅行,只是没有回忆。

不好比喻,但我希望这能让你体会到它们之间的区别。

答案 1 :(得分:12)

我认为viewsbreakOut不相同。

breakOut是一个CanBuildFrom实现,用于通过消除中间步骤来简化转换操作。例如,在没有中间收集的情况下从A到B. breakOut表示让Scala选择适当的构建器对象,以便在给定方案中生成新项目的效率最高。更多详情here

views处理不同类型的效率,主要的销售宣传是:“不再有新的对象”。视图存储对对象的轻量级引用,以处理不同的使用场景:延迟访问等。

底线:

如果在mapview,您可能仍会获得在生成预期结果之前创建的中间参考集合。您仍然可以从以下方面获得出色的表现:

collection.view.map(somefn)(breakOut)

比起:

collection.view.map(someFn)

答案 2 :(得分:1)

黄色人说的是什么。

视图的一个用例是节省内存。例如,如果您有一个长度为百万字符的字符串original,并且需要逐个使用该字符串的所有百万个后缀,则可以使用

的集合。
val v = original.view
val suffixes = v.tails

对原始字符串的观点。然后你可以逐个遍历后缀,使用suffix.force()将它们转换回循环中的字符串,因此一次只能在内存中保存一个。当然,你可以通过在原始字符串的索引上迭代你自己的循环来做同样的事情,而不是创建任何类型的后缀集合。

另一个用例是当派生对象的创建成本很高时,你需要在集合中(例如,作为地图中的值),但是你只会访问一些,而你不知道哪些。

如果你真的有一个案例,他们之间的选择是有道理的,宁愿 breakOut ,除非有一个很好的论据,使用 view (如上所述)。

  • 观看需要更多代码更改和关注,而不是 breakOut ,因为您需要在需要时添加 force()。根据具体情况,未能这样做 通常只在运行时检测到。使用 breakOut ,通常如果它 编译,这是对的。
  • 如果视图不适用, breakOut 会更快,因为跳过了视图生成和强制。
  • 如果使用调试器,则可以检查收集内容 不能有意义地处理一系列观点。

答案 3 :(得分:1)

从Scala 2.13开始,这不再是一个问题。分组讨论已删除,建议使用视图替换。


Scala 2.13 Collections Rework

视图也是collection.breakOut的推荐替代。  例如,

val s: Seq[Int] = ... 
val set: Set[String] = s.map(_.toString)(collection.breakOut)

可以表示为具有以下相同的性能特征:

val s: Seq[Int] = ... 
val set = s.view.map(_.toString).to(Set)
相关问题