在以下代码行中,我期待的结果与实际结果不同。有人能帮助我理解为什么吗?
array1 = [["a", "b", "c"], ["a", "b", "c"]]
temp1 = ["x", "y", "z"]
array1 << temp1
2.times do
temp1[0] = gets.chomp #first loop enter 1 and then 4
temp1[1] = gets.chomp #first loop enter 2 and then 5
temp1[2] = gets.chomp #first loop enter 3 and then 6
puts temp1.inspect
array1 << temp1
puts array1.inspect
# Actual result: [["a", "b", "c"], ["a", "b", "c"], ["4", "5", "6"], ["4", "5", "6"], ["4", "5", "6"]]
# Expected Result: [["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"], ["4", "5", "6"]]
end
答案 0 :(得分:4)
执行此操作并将其工作(将.clone添加到temp1
的所有引用):
array1 = [["a", "b", "c"], ["a", "b", "c"]]
temp1 = ["x", "y", "z"]
array1 << temp1.clone
2.times do
temp1[0] = gets.chomp #first loop enter 1 and then 4
temp1[1] = gets.chomp #first loop enter 2 and then 5
temp1[2] = gets.chomp #first loop enter 3 and then 6
puts temp1.inspect
array1 << temp1.clone
puts array1.inspect
end
# Actual result: [["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"], ["4", "5", "6"]]
# Expected Result: [["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"], ["4", "5", "6"]]
基本上,当您在temp1
中附加array1
时,它会通过引用而不是按值发生。因此,每当temp1更新时,array1中相应的附加条目也将自动更新。要防止此行为,您需要在将对象附加到数组之前clone
/ dup
。 clone
/ dup
复制对象(因此它没有相同的引用/ object_id),然后分配它。
有关详细说明,请查看this帖子。
答案 1 :(得分:2)
每当遇到类似这样的问题时,添加一些代码就可以在计算的每个步骤中打印出每个感兴趣对象的object_id
,这是有益的。每个Ruby对象都有一个唯一的object_id
。可以使用方法Object.object_id检索id:
{ "a"=>1 }.object_id
#=> 70225550848400
让我们试一试。 (我已将object_id
缩短为最后三位数,以便更容易看到它们何时发生变化。)
array1 = [["a", "b", "c"], ["a", "b", "c"]]
puts "1a array1.object_id=#{array1.object_id % 1000}"
puts "1b array1.map(&:object_id)=#{array1.map { |e| e.object_id % 1000 } }"
puts
temp1 = ["x", "y", "z"]
puts "2a temp1.object_id=#{temp1.object_id % 1000}"
array1 << temp1
puts "2b array1=#{array1.inspect}"
puts "2c array1.object_id=#{array1.object_id % 1000}"
puts "2d array1.map(&:object_id)=#{array1.map { |e| e.object_id % 1000 } }"
puts
2.times do
temp1[0] = gets.chomp
temp1[1] = gets.chomp
temp1[2] = gets.chomp
puts "3a temp1=#{temp1.inspect}"
puts "3b temp1.object_id=#{temp1.object_id % 1000}"
array1 << temp1
puts "3c array1=#{array1.inspect}"
puts "3d array1.object_id=#{array1.object_id % 1000}"
puts "3e array1.map(&:object_id)=#{array1.map { |e| e.object_id % 1000 } }"
puts
end
打印
1a array1.object_id=900
1b array1.map(&:object_id)=[0, 920]
2a temp1.object_id=480
2b array1=[["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"]]
2c array1.object_id=900
2d array1.map(&:object_id)=[0, 920, 480]
1
2
3
3a temp1=["1", "2", "3"]
3b temp1.object_id=480
3c array1=[["a", "b", "c"], ["a", "b", "c"], ["1", "2", "3"], ["1", "2", "3"]]
3d array1.object_id=900
3e array1.map(&:object_id)=[0, 920, 480, 480]
4
5
6
3a temp1=["4", "5", "6"]
3b temp1.object_id=480
3c array1=[["a", "b", "c"], ["a", "b", "c"], ["4", "5", "6"], ["4", "5", "6"],
["4", "5", "6"]]
3d array1.object_id=900
3e array1.map(&:object_id)=[0, 920, 480, 480, 480]
你需要仔细研究这个。
要了解发生了什么,将数组视为容器可能会有所帮助。你所做的是更改容器的内容,但不更改容器本身,但array1
是容器列表。
要使代码正常工作,您只需更改容器和内容即可。一种简单的方法是替换:
temp1[0] = gets.chomp
temp1[1] = gets.chomp
temp1[2] = gets.chomp
与
temp1 = [gets.chomp, gets.chomp, gets.chomp]
array1 = [["a", "b", "c"], ["a", "b", "c"]]
puts "1a array1.object_id=#{array1.object_id % 1000}"
puts "1b array1.map(&:object_id)=#{array1.map { |e| e.object_id % 1000 } }"
puts
temp1 = ["x", "y", "z"]
puts "2a temp1.object_id=#{temp1.object_id % 1000}"
array1 << temp1
puts "2b array1=#{array1.inspect}"
puts "2c array1.object_id=#{array1.object_id % 1000}"
puts "2d array1.map(&:object_id)=#{array1.map { |e| e.object_id % 1000 } }"
puts
2.times do
temp1 = [gets.chomp, gets.chomp, gets.chomp]
puts "3a temp1=#{temp1.inspect}"
puts "3b temp1.object_id=#{temp1.object_id % 1000}"
array1 << temp1
puts "3c array1=#{array1.inspect}"
puts "3d array1.object_id=#{array1.object_id % 1000}"
puts "3e array1.map(&:object_id)=#{array1.map { |e| e.object_id % 1000 } }"
puts
end
打印
1a array1.object_id=100
1b array1.map(&:object_id)=[220, 120]
2a temp1.object_id=660
2b array1=[["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"]]
2c array1.object_id=100
2d array1.map(&:object_id)=[220, 120, 660]
1
2
3
3a temp1=["1", "2", "3"]
3b temp1.object_id=800
3c array1=[["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"]]
3d array1.object_id=100
3e array1.map(&:object_id)=[220, 120, 660, 800]
4
5
6
3a temp1=["4", "5", "6"]
3b temp1.object_id=580
3c array1=[["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"],
["4", "5", "6"]]
3d array1.object_id=100
3e array1.map(&:object_id)=[220, 120, 660, 800, 580]