更改克隆对象的值

我有一个对象,它有一个名为my_array的实例变量数组。 我通过attr_accessor声明它。

 my_object.my_array = [1,2,3] # <= I don't know the max size of my_array(it can be dynamic) 

我想用my_object创建相同的对象,并用my_array填充只有一个元素。 该元素内的值是my_array元素(来自my_object )的每个值。 因为my_array的大小是动态的,所以我想我需要通过each迭代它。

这是我的尝试:

 my_object.my_array.each do |element| # <= my_object is a special object new_object = nil unless new_object.nil? new_object = my_object.clone # <= I create new object with same class with my_object new_object.my_array.clear # <= clear all element inside it. new_object.my_array.push(element) # assign element value to the first element. # rest of code # new_object = nil end 

迭代没有正确迭代。 my_object.my_array的大小是3,然后它应该迭代三次,但它不是,它只迭代一次。 我相信这是因为new_object.my_array.clear ,但是我从my_object克隆了它,为什么会发生这种情况呢?

问题是, clone将成为浅克隆,而不是深克隆。 换句话说, my_array是一个引用,克隆的实例引用内存中的相同数组。 考虑:

 class MyClass attr_accessor :my_array end a = MyClass.new a.my_array = [1, 2, 3] a.my_array #=> [1, 2, 3] b = a.clone b.my_array.push(4) b.my_array #=> [1, 2, 3, 4] a.my_array # also changed! #=> [1, 2, 3, 4] 

为了解决这个问题,您需要扩展initialize_copy方法以克隆数组:

 class MyClass attr_accessor :my_array def initialize_copy(orig) super self.my_array = orig.my_array.clone end end a = MyClass.new a.my_array = [1, 2, 3] a.my_array #=> [1, 2, 3] b = a.clone b.my_array.push(4) b.my_array #=> [1, 2, 3, 4] a.my_array # did not change, works as expected #=> [1, 2, 3] 

当您指定一个数组时,它只复制引用,并且它们都指向相同的引用,因此当您打印其中任何一个时,会反映出一个更改:

 orig_array = [1,2,3,4]
another_array = orig_array puts orig_array.unshift(0).inspect puts another_array.inspect

哪个输出:

 [0, 1, 2, 3, 4] [0, 1, 2, 3, 4] 

为避免这种情况,您可以使用Marshal从原始数组进行复制,而不会影响复制到的对象。 原始数组中的任何更改都不会更改复制到的对象。

 orig_array = [1,2,3,4] another_array = Marshal.load(Marshal.dump(orig_array)) puts orig_array.unshift(0).inspect puts another_array.inspect 

哪个输出:

 [0, 1, 2, 3, 4] [1, 2, 3, 4]