我有一个对象,它有一个名为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
克隆的,为什么会发生这种情况呢?
答案 0 :(得分:1)
当您指定一个数组时,它只复制引用,并且它们都指向相同的引用, 因此,当您打印其中任何一个时,都会反映出一个变化:
orig_array = [1,2,3,4]<br>
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]
答案 1 :(得分:0)
问题是,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]