更改克隆对象的值
我有一个对象,它有一个名为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]