在Ruby中创建副本

时间:2014-05-21 18:25:38

标签: ruby

我将以下代码作为示例。

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的版本使用的事实有关,或者甚至因为它是一个多维数组,不像前面的例子?

1 个答案:

答案 0 :(得分:3)

变量名称或“引用”对象 1 。在上面的代码中,相同的对象(有两个名称,ab)正在更改。

在这种情况下,一个简单的解决方案是制作原始Array 对象的(浅)副本,例如b = a.dupb = 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 我发现谈论变量是名称最为统一,因为这样的概念可以应用于多种语言 - 这里的关键是任何对象都可以有一个或多个名称,就像一个人可以有很多绰号。如果一个对象的名称为零,那么它就不再是强烈可达的,就像一个人一样,被遗忘了。

但是,查看变量(命名对象)的另一种方法是它们包含引用值,其中引用值标识对象。这导致了诸如

之类的措辞
  • “变量a包含对象x” - 或,
  • 的引用[值]
  • “变量a引用/引用对象x” - 或者,根据我的喜好,
  • “变量a是对象x的名称。”

对于大小写或不可变的“原始”或“立即”值,底层机制略有不同,但是,不可变的对象值不能改变,并且这种缺乏共享的对象性质不会表现出来。


另见:


2 根据嵌套数组的更新问题,前面的规则解释了这一点 - 变量(嗯,真正的表达式)仍然命名为共享对象。在任何情况下,使用“克隆数组数组”(到两个级别,但不是递归)的一种方法是使用:

b = a.map {|r| r.dup}

这是因为Array#map返回一个带有映射值的新数组,在这种情况下,它们是相应嵌套数组的重复(浅克隆)。

请参阅How to create a deep copy of an object in Ruby?了解其他“深[er]复制”方法 - 特别是如果数组(或影响可变对象)嵌套到N级别。