temp
得到@board.dup
, @board
数组被修改。然而,temp
也被修改了!我已经试着阅读了所有的相关文档,但还是找不到解释。
class Test
def initialize
@board = [[1,2],[3,4], [5,6]]
end
def modify
temp = @board.dup #Also tried .clone
print 'temp: ';p temp
print '@board: ';p @board
@board.each do |x|
x << "x"
end
print "ntemp: ";p temp
print '@board: ';p @board
end
end
x = Test.new
x.modify
输出:temp: [[1, 2], [3, 4], [5, 6]]
@board: [[1, 2], [3, 4], [5, 6]]
temp: [[1, 2, "x"], [3, 4, "x"], [5, 6, "x"]] # <= Why did it change?
@board: [[1, 2, "x"], [3, 4, "x"], [5, 6, "x"]]
我能做些什么来确保temp不被修改?
你有数组数组,所以你把第一个数组,但内部对象指向同一个实例。在本例中,您只需修改相同的源代码。
像:
arr = [[1, 2, 3]]
arr2 = arr.dup
arr2[0] << 1
p arr
# => [[1, 2, 3, 1]]
p arr2
# => [[1, 2, 3, 1]]
所以你必须使用dup
对于所有的数组实例,像这样。
arr = [[1, 2, 3]]
arr3 = arr.map(&:dup)
arr3[0] << 1
p arr
# => [[1, 2, 3]]
p arr3
# => [[1, 2, 3, 1]]
在你的情况下,使用这个map
。
class Test
def initialize
@board = [[1,2],[3,4], [5,6]]
end
def modify
temp = @board.map(&:dup) # dup all
print 'temp: ';p temp
print '@board: ';p @board
@board.each do |x|
x << "x"
end
print "ntemp: ";p temp
print '@board: ';p @board
end
end
x = Test.new
x.modify
# temp: [[1, 2], [3, 4], [5, 6]]
# @board: [[1, 2], [3, 4], [5, 6]]
#
# temp: [[1, 2], [3, 4], [5, 6]]
# @board: [[1, 2, "x"], [3, 4, "x"], [5, 6, "x"]]
原因是clone
和dup
产生一个浅拷贝。因此,内部数组的对象id仍然是相同的:它们是相同的数组。
你需要的是深度克隆。在标准库中没有内置方法能够做到这一点。
From the docs:
dup
生成obj的浅拷贝——obj的实例变量被复制,但不复制它们引用的对象。
也就是说:你需要对你的数组做一个深度拷贝。
当你使用ActiveSupport gem (Rails)时,你可以使用它的deep_dup
方法,而不仅仅是调用dup
:
temp = @board.deep_dup
如果没有gem, mashashing可能是一种简单的解决方案,可以在不了解对象内部的情况下深入处理几乎所有内容:
temp = Marshal.load(Marshal.dump(@board))
您可以为嵌套数组添加deep_dup方法:
class Array
def deep_dup
map {|x| x.deep_dup}
end
end
# To handle the exception when deepest array contains numeric value
class Numeric
def deep_dup
self
end
end
class Test
def initialize
@board = [[1,2], [3,4], [5,6]]
end
def modify
temp = @board.deep_dup
...
end
end
x = Test.new
x.modify
# temp: [[1, 2], [3, 4], [5, 6]]
# @board: [[1, 2], [3, 4], [5, 6]]
# temp: [[1, 2], [3, 4], [5, 6]]
# @board: [[1, 2, "x"], [3, 4, "x"], [5, 6, "x"]]