scala.collection.breakOut vs views



此答案描述了如何使用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)

视图解决了相同的问题,此外,又有访问元素:

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

我假设View包装器的创建相当便宜,所以我的问题是:是否有真正的理由在View S?

上使用breakOut

您将从英格兰到法国旅行。

带有视图:您正在笔记本和繁荣中的一组笔记,一旦您打电话给.force(),您就开始制作所有内容:buy a ticket, board on the plane, ....

突破性:您正在离开和繁荣时,您在巴黎看着埃菲尔铁塔。您不记得您到底是怎么到达那里的,但是实际上您没有留下任何回忆。

不好的类比,但我希望这可以让您对它们之间的区别有何不同。

我不认为viewsbreakOut是相同的。

breakOutCanBuildFrom实现,用于通过消除中介步骤来简化变换操作。例如,没有中介集合从A到B。breakOut意味着让Scala选择适当的构建器对象,以在给定情况下最大程度地生产新项目的效率。更多详细信息在这里

views处理不同类型的效率,主要的销售音调是:"不再有新对象"。视图存储对对象的灯光引用以应对不同的用法方案:懒惰访问等。

底线:

如果您在view上的map,则可能仍会在产生预期结果之前获得中介集合。您仍然可以从:

中获得卓越的性能
collection.view.map(somefn)(breakOut)

比:

collection.view.map(someFn)

从Scala 2.13开始,这不再是一个问题。突破已被删除,视图是建议的替换。


Scala 2.13收藏率返工

视图也是推荐的替换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)

Flavian所说的。

一个用例以保存内存。例如,如果您有一百万个字符长的字符串original,并且需要一个一个一个字符串的所有后缀,则需要使用一个

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

在原始字符串上查看。然后,您可以使用suffix.force()将它们转换回循环中的字符串,因此一次只能将其转换为一个,因此一次只能将一个固定在内存中。当然,您可以通过在原始字符串的索引上迭代迭代来做同样的事情,而不是创建任何类型的后缀集合。

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

如果您确实有一种有意义的选择,则选择 Breakout ,除非有一个很好的论点用于使用 view (如上所述)。

  • 视图需要比 Breakout 更多的代码更改和护理,因为您需要在需要时添加 force()。根据上下文,不这样做是通常只在运行时检测到。使用突破,通常编译,是的。
  • 在视图不适用的情况下, Breakout 由于视图生成和强迫被跳过,因此会更快。
  • 如果您使用调试器,则可以检查收集内容,无法有意义地使用视图集合。

最新更新