Ruby-在更改实例变量时修改局部变量
Ruby-在更改实例变量时修改局部变量,ruby,variables,scope,instance-variables,Ruby,Variables,Scope,Instance Variables,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 '@b
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
类测试
def初始化
@董事会=[[1,2]、[3,4]、[5,6]]
结束
def修改
temp=@board.dup#也尝试过。克隆
打印“温度:”;p温度
打印“@board:”;p@board
@董事会,每个董事会| x|
x原因是clone
和dup
产生浅拷贝。因此,内部数组的对象ID仍然是相同的:它们是相同的数组
你需要的是一个深度克隆。标准库中没有内置方法可以做到这一点。来自:
dup
生成obj的浅层副本obj的实例变量被复制,但它们引用的对象不被复制
这就是说:您需要制作阵列的深度副本
使用ActiveSupport gem(Rails)时,您可以使用其deep\u dup
方法,而不只是调用dup
:
temp = @board.deep_dup
如果不使用gems,mashaling可能是一个简单的解决方案,可以在不了解对象内部结构的情况下实现几乎所有的深度dup:
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"]]
您有一个带数组的数组,所以您复制了第一个数组,但在对象内部指向同一个实例。在这种情况下,您只需修改相同的源
就像这里:
arr = [[1, 2, 3]]
arr2 = arr.dup
arr2[0] << 1
p arr
# => [[1, 2, 3, 1]]
p arr2
# => [[1, 2, 3, 1]]
在您的情况下,请使用此映射
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"]]
类测试
def初始化
@董事会=[[1,2]、[3,4]、[5,6]]
结束
def修改
温度=@board.map(&:dup)#dup all
打印“温度:”;p温度
打印“@board:”;p@board
@董事会,每个董事会| x|
它是相同的参考,例如,temp
指向相同的阵列@board
是。如果你想保留原始版本,那么你必须克隆它。对不起,编辑了我的问题。我确实在代码中执行了@board.dup
。但是临时工也换了。(也尝试了.clone
,仍然是相同的输出)你必须克隆deep。封送
在这种情况下是OP。@LukasBaliak:但是香草ruby没有比这更好的了。@SergioTulentsev完全转储所有deep对象是的,但在这种情况下我认为是一个很小的OP。@LukasBaliak:我有点同意你的看法。但我更喜欢写的答案不仅适用于特定的例子。未来的其他读者可能会有一个稍微不同的问题,可能会对更普遍的解决方案感兴趣。
arr = [[1, 2, 3]]
arr3 = arr.map(&:dup)
arr3[0] << 1
p arr
# => [[1, 2, 3]]
p arr3
# => [[1, 2, 3, 1]]
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"]]