在 Scala 中添加不可变集合时,幕后发生了啥?

Posted

技术标签:

【中文标题】在 Scala 中添加不可变集合时,幕后发生了啥?【英文标题】:What goes on behind the scenes when adding immutable collections in Scala?在 Scala 中添加不可变集合时,幕后发生了什么? 【发布时间】:2018-01-26 03:59:47 【问题描述】:

在 Scala 中工作时,我遇到了不可变项,例如 immutable.Map。有时我无法控制的代码 (Spark) 返回一个 immutable.Map,我也想处理和添加元素。我正在使用以下方法,因为它可以编译并运行。我希望计算机足够聪明,可以有效地完成这项工作,但不相信我应该做出这样的假设。

var map: immutable.Map[Int, Double] = getMapFromSomewhere()
var i = 0
while(i < 5)
    map += (i -> 0.0)
    i +=1

我希望这会将我的新地图项放入内存中,并且不会复制地图,必须通过垃圾收集进行清理。我应该从我的immutable.Map 创建一个mutable.Map 来执行这些类型的操作吗?

【问题讨论】:

【参考方案1】:

当您“添加”到不可变集合时,您实际上是在创建一个新集合,理想情况下,它通常与旧集合共享相同的内存和数据。这是安全的,因为集合是不可变的,您不必担心更改其中一个会损坏另一个。

您的代码...不是很好。这对 Scala 来说是一种非常丑陋的风格,而且你的类型已经关闭。 (没有“immutable.Map[Double]”之类的东西,因为Map 有两个类型参数。我猜你正在构建一个immutable.Map[Int,Double]。)

这是一种不那么丑陋的方式来构建您正在尝试构建的内容:

(0 until 5).map( i => (i, 0.0) ).toMap

或者,更准确地说,因为您可能从非空地图开始

getMapFromSomwhere() ++ (0 until 5).map(i =>(i, 0.0))

为您真正需要的特殊情况保留可变数据结构,并且只有在您仔细考虑了如何管理任何并发性或者您可以保证不会有并发访问时才使用它们。您在 Scala 中的默认设置应该是以函数式风格构建和操作的不可变数据结构,避免在您的示例中进行显式的外部迭代。您应该很少使用关键字“var”,例如可变数据结构,仅用于您仔细考虑过的特殊情况。

【讨论】:

很抱歉这个丑陋的循环,感谢反馈。修复了我的示例中的地图,只是在随意处理代码时出现了拼写错误。感谢您确认更新 immutable 的过程不会像担心的那样对我的记忆产生负面影响。【参考方案2】:

函数式编程语言中的数据结构不仅是不可变的(它们的引用一旦创建就不能更改),而且是持久的。通过持久化方式,它为某些操作重用现有集合。例如,在 Scala 中,将元素添加到列表是经过优化的(因此,当您使用列表时,您应该将添加操作视为将元素推入堆栈的一种)。

同样,其他集合也针对其他操作进行了优化。 我给了你一些参考资料,可以帮助你更好地理解函数式编程中的持久数据结构。

    Persistent data structures in Scala 2.https://www.packtpub.com/mapt/book/application_development/9781783985845/3/ch03lvl1sec25/persistent-data-structures https://www.youtube.com/watch?v=pNhBQJN44YQ https://www.youtube.com/watch?v=T0yzrZL1py0

【讨论】:

以上是关于在 Scala 中添加不可变集合时,幕后发生了啥?的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 中删除内存映射文件 - 幕后发生了啥?

我在处理这个 Scala 集合时做错了啥?

lock 语句在幕后做了啥?

如何在Scala中添加另一个参数时传递可变参数?

Scala 系列—— 集合类型综述

Scala的集合