我将以下代码作为示例。
a = [2]
b = a
puts a == b
a.each do |num|
a[0] = num-1
end
puts a == b
我希望b
引用a
的值,b
的值在a
更改时不会更改。(第二个{ {1}}应该返回false)。
提前谢谢。
已编辑 -
user2864740发布的答案似乎适用于我给出的示例。但是,我正在开发一个数独解决方案,它似乎并没有在那里工作。
puts
这是否与我使用全局变量或Ruby I的版本使用的事实有关,或者甚至因为它是一个多维数组,不像前面的例子?
答案 0 :(得分:3)
变量名称或“引用”对象 1 。在上面的代码中,相同的对象(有两个名称,a
和b
)正在更改。
在这种情况下,一个简单的解决方案是制作原始Array 对象的(浅)副本,例如b = a.dup
或b = Array.new(a)
。 (使用浅拷贝,数组中的元素也是共享的,并且将显示与原始问题类似的音素,除非它们[递归]重复,等等。 2 )
a = [2]
b = Array.new(a) # create NEW array object, a shallow-copy of `a`
puts a == b # true (same content)
puts a.equal?(b) # false (different objects)
a.each do |num|
a[0] = num-1 # now changing the object named by `a` does not
# affect the object named by `b` as they are different
end
puts a == b # false (different content)
这个“命名”现象的一个孤立的例子(见different equality forms):
a = []
b = a # assignment does NOT make a copy of the object
a.equals?(b) # true (same object)
c = a.dup # like Array.new, create a new shallow-copy object
a.equals?(c) # false (different object)
1 我发现谈论变量是名称最为统一,因为这样的概念可以应用于多种语言 - 这里的关键是任何对象都可以有一个或多个名称,就像一个人可以有很多绰号。如果一个对象的名称为零,那么它就不再是强烈可达的,就像一个人一样,被遗忘了。
但是,查看变量(命名对象)的另一种方法是它们包含引用值,其中引用值标识对象。这导致了诸如
之类的措辞对于大小写或不可变的“原始”或“立即”值,底层机制略有不同,但是,不可变的对象值不能改变,并且这种缺乏共享的对象性质不会表现出来。
另见:
2 根据嵌套数组的更新问题,前面的规则解释了这一点 - 变量(嗯,真正的表达式)仍然命名为共享对象。在任何情况下,使用“克隆数组数组”(到两个级别,但不是递归)的一种方法是使用:
b = a.map {|r| r.dup}
这是因为Array#map返回一个带有映射值的新数组,在这种情况下,它们是相应嵌套数组的重复(浅克隆)。
请参阅How to create a deep copy of an object in Ruby?了解其他“深[er]复制”方法 - 特别是如果数组(或影响可变对象)嵌套到N级别。