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"]]
我可以做些什么来确保温度不会被修改?
答案 0 :(得分:1)
你有阵列数组,所以你复制了第一个数组,但是在对象里面指向同一个实例。在这种情况下,您只需修改相同的源。
喜欢这里:
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"]]
答案 1 :(得分:0)
原因是clone
和dup
产生浅拷贝。因此,内部数组的对象id仍然是相同的:那些是相同的数组。
你需要的是一个深刻的克隆。标准库中没有内置的方法可以做到这一点。
答案 2 :(得分:0)
来自docs:
dup
生成obj的浅表副本 - 复制obj的实例变量,但不复制它们引用的对象。
说:你需要制作阵列的深层副本。
当您使用ActiveSupport gem(Rails)时,您可以使用其deep_dup
方法而不是仅调用dup
:
temp = @board.deep_dup
没有宝石mashaling可能是一个简单的解决方案,深入复制几乎所有东西,而不知道对象的内部:
temp = Marshal.load(Marshal.dump(@board))
答案 3 :(得分:0)
您可以为嵌套数组添加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"]]