背景
我有一大堆代码看起来像这样:
val big_obj = new BigObj
big_obj.recs[5].foo()
... // other code
big_obj.recs[7].bar()
问题
我想做这样的事情
val big_obj = new BigObj
alias ref = big_obj.recs // looking for something like an alias
ref[5].foo()
... // other code
ref[7].bar()
因为我害怕复制大对象(来自C ++)。但后来我意识到Scala可能很聪明,如果我只是这样做:
val big_obj = new BigObj
val ref = big_obj.recs // no copies made?
编译器可能足够智能,无论如何都不能复制,因为它只是只读的。
问题
这让我想起了Scala的记忆模型。
在什么情况下会制作/不制作副本?
我正在寻找一个简单的答案或经验法则,当我处理really_big_objects时,无论何时我进行任务,包括传递参数,我都可以记住这一点。
答案 0 :(得分:4)
就像Java(和python以及可能还有很多其他语言)一样,副本永远不会是对象。分配对象或将其作为参数传递时,它只复制对象的引用;实际的对象只是位于内存中,并有一个额外的东西指向它。唯一可以复制的东西是原语(整数,双精度等)。
正如你所指出的,这对于不可变对象显然是有益的,但它对所有对象都是正确的,甚至是可变对象:
scala> val a = collection.mutable.Map(1 -> 2)
a: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2)
scala> val b = a
b: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2)
scala> b += (2 -> 4)
res41: b.type = Map(2 -> 4, 1 -> 2)
scala> a
res42: scala.collection.mutable.Map[Int,Int] = Map(2 -> 4, 1 -> 2)
scala> def addTo(m: collection.mutable.Map[Int,Int]) { m += (3 -> 9) }
addTo: (m: scala.collection.mutable.Map[Int,Int])Unit
scala> addTo(b)
scala> a
res44: scala.collection.mutable.Map[Int,Int] = Map(2 -> 4, 1 -> 2, 3 -> 9)