【问题标题】:Scala collections, references, and memory efficiencyScala 集合、引用和内存效率
【发布时间】:2014-09-07 09:52:24
【问题描述】:

Scala 集合是否只能初始化/分配 vals、vars 和 literals 的字面量值,而不是 vals/vars 本身?

即下面的列表b 将是(4, 3),并且没有办法从集合中替代引用a 而不是在集合中托管它的值?

val a = 3
val b = List(4, a)

我是否应该假设“完成”此类引用的唯一方法是从数据切换到对象,因为默认情况下大多引用对象?在性能很重要的地方,使用对象可能不是非常高效的计算和内存。

关于纯粹的性能方面,假设a 是一些大型集合而不仅仅是一个数字,当b 的上述初始化发生时,Scala 会在内存中复制其“内容”吗?

谢谢!

【问题讨论】:

  • vals 和 vars 是引用(分别是不可变和可变的),您可以像添加 a 一样将它们添加到集合中。你能澄清一下这个问题吗?

标签: scala scala-2.10


【解决方案1】:

当您调用List 的构造函数时,它的参数会立即被评估(按值调用),因此对象3 将存储在List 中。

一般来说,scala 中的所有内容都是一个对象(撇开 JVM 表示细节不谈),所以您存储的是对 3 的不可变引用,而这又是不可变的。

另外,请注意 - 由于 referencial transparencya 是对 3 的常量引用) - 存储对 a 的引用或其引用的对象没有任何区别,即它是“透明”。

因此,如果您想要一个不透明的引用,您可以稍后更改,您始终可以存储对可变对象的常量引用:

scala> class Foo(var foo: Int)
defined class Foo

scala> val x = new Foo(42)
x: Foo = Foo@3a654e77

scala> val a = List(x)
a: List[Foo] = List(Foo@3a654e77)

scala> a.head.foo
res25: Int = 42

scala> x.foo = 43
x.foo: Int = 43

scala> a.head.foo
res26: Int = 43

但那是邪恶的男孩!


根据性能问题,如果a 是一个大型不可变 集合,引用透明性允许在构造b 时重用现有集合a,而不是悲观地复制它。由于a 不能变异,所以根本不需要克隆。

您可以在 REPL 中轻松测试:

让我们创建一个不可变集合a

scala> val a = List(1, 2)
a: List[Int] = List(1, 2)

让我们使用a 来创建b

scala> val b = List(a, List(3, 4))
b: List[List[Int]] = List(List(1, 2), List(3, 4))

b 的第一个元素一模一样就是我们说的a

scala> b.head eq a
res18: Boolean = true

注意eq比较引用相等,所以上面不只是a的副本。进一步证明:

scala> List(1, 2) eq a
res19: Boolean = false

【讨论】:

  • 很高兴收到您对我在下面添加的增强功能的评论。否则再次感谢...
【解决方案2】:

感谢@Gabriele Petronella 的精彩回答。这无法格式化为评论,所以我只是在此处添加它作为补充。

我认为更进一步的参考点,以下内容也可能非常有用,尽管eq 在这里插入有点困难。

scala> val a = MutableList(1,2) 
a: scala.collection.mutable.MutableList[Int] = MutableList(1, 2) 

scala> val b = List(a, 3, 4) 
b: List[Any] = List(MutableList(1, 2), 3, 4) 

scala> a += 100
res20: a.type = MutableList(1, 2, 100) 

scala> b 
res21: List[Any] = List(MutableList(1, 2, 100), 3, 4) 

不确定如何表述与引用透明度的关系 - 但它确实与原始问题有关

【讨论】:

  • 是的,您的示例与我的第一个示例基本相同。不可变列表可以存储对可变对象的不可变引用(我知道这个措辞很复杂),并且您绝对可以改变它们指向的这些可变对象。引用没有改变,但是被引用的对象已经改变了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-20
  • 2013-07-27
  • 2013-01-31
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
相关资源
最近更新 更多