在编写程序时,我发现了一些有趣的东西。如果我定义a = b
,<<
对b
的任何更改都会反映在a
中,反之亦然。
Ruby是否不会创建b的重复自治副本并将其以不同方式存储在?
中如果没有,当我在主阵列上进行操作时,如何在特定时间点存储阵列的未被篡改的快照?
>> a = b = [0, 1]
=> [0, 1]
>> a
=> [0, 1]
>> b
=> [0, 1]
# so far so good
>> a << 2
=> [0, 1, 2]
>> a
=> [0, 1, 2]
>> b
=> [0, 1, 2]
# huh?! that can't be right, lemme try this the other way around
>> b << 3
=> [0, 1, 2, 3]
>> a
=> [0, 1, 2, 3]
>> b
=> [0, 1, 2, 3]
# what is going on here?!
答案 0 :(得分:3)
使用Object#dup
。
NB 它确实创建了一个浅拷贝;要创建一个深层副本,需要自己实现该副本。
▶ b = [0, 1]
#⇒ [ 0, 1 ]
▶ a = b.dup
#⇒ [ 0, 1 ]
▶ b << 2
#⇒ [ 0, 1, 2 ]
▶ a
#⇒ [ 0, 1 ]
要制作冻结和污染的副本,请使用Object#clone
。
答案 1 :(得分:1)
a
和b
指向内存中的同一个对象。如果你想要一个对象的副本而不影响你可以做的原始对象
b = a.dup
答案 2 :(得分:0)
让我试着澄清这里到底发生了什么。这是引用的基本概念,由许多语言实现。当您创建“数组”时,该数组值是匿名内存对象,并且在您的代码中,a
和b
都引用相同的对象。该语言使用“引用计数”的一些变体来跟踪存在多少引用,以便知道值何时被“孤立”并且可以被垃圾收集。
这种所谓的“浅层复制”非常有效,而且往往正是所需要的。所以,这是默认情况下这些语言的作用。
当您创建“深层复制”时,您有意识地复制匿名内存对象。现在,a
指向一个,b
指向另一个对象(在那个时刻)是第一个对象的快照。相比之下,这是一个耗时的过程,当然,它会分配更多的内存。现在,对一个数组所做的更改(当然)不会反映在另一个数组中,因为它们现在是两个完全不同的东西。由于这是一个不那么常见的事情,因此该语言提供了一些明确的方式来指定您想要这样做。
Ruby ... PHP ... Perl ......几乎每个人都做这样的事情。
(并且, en passant,让我也说他们实施了“强”与“弱”的引用。但是,这是另一天的另一个故事。)
编辑: 此回复部分不正确!请注意随后在此帖子附带的第一条评论中进行的更正。(并且,“谢谢你让我直截了当!”)关键点(它是一个键点...),与前面提到的匿名内存对象包含的内容有关。(它们本身可能包含“引用”。数组经常会这样做!所以,你可以找到“两个独立的内存对象”,引用相同的东西。 Ergo,即使它们确实是“两个完全独立的对象”,但它们在你的程序中实际使用时仍然会相互冲突。(而且,嘿,调试这些东西很有趣。)