我想创建一个像这样的哈希数组:
[
{"start"=>1, "end"=>2},
{"start"=>2, "end"=>3},
{"start"=>3, "end"=>4},
{"start"=>4, "end"=>5},
{"start"=>5, "end"=>6}
]
当我尝试这段代码时:
foo = 1
bar = 2
hash = {}
array = []
5.times do
hash['start'] = foo
hash['end'] = bar
array << hash
foo += 1
bar += 1
end
hash
值在array
内更改,同时向其添加循环和哈希值。 array
成为:
[
{"start"=>5, "end"=>6},
{"start"=>5, "end"=>6},
{"start"=>5, "end"=>6},
{"start"=>5, "end"=>6},
{"start"=>5, "end"=>6}
]
为什么会在以下情况发生:
foo = 1
array = []
5.times do
array << foo
foo += 1
end
array # => [1, 2, 3, 4, 5]
在循环期间不会更改array
内的数字?
答案 0 :(得分:3)
这是因为哈希是可变的。如果您有foo = {"start" => 1}
,并执行foo["start"] += 1
,那么foo
仍指向相同的哈希,尽管它已修改为{"start" => 2}
。它不会改变参考。如果你在一个数组中有这个相同对象的多个副本并更改其中一个,那么所有这些副本都将被修改。
另一方面,数字不可变;如果您有foo = 1
,并且foo += 1
,那么foo
现在将指向2
,这是与1
不同的对象。
答案 1 :(得分:2)
您每次都可以创建一个新哈希。
foo = 1
array = []
5.times do
array << { 'start' => foo, 'end' => foo + 1 }
foo += 1
end
答案 2 :(得分:1)
使用:
array << hash.dup
而不是:
array << hash
因为你在这里添加了对hash的引用,而不是hashs本身。
答案 3 :(得分:1)
您应该更改代码以在每次循环迭代中创建新哈希:
foo = 1
bar = 2
array = []
5.times do
hash = {}
hash['start'] = foo
hash['end'] = bar
array << hash
foo += 1
bar += 1
end
puts array
否则,您总是更改同一个对象,这就是您以与数组元素相同的哈希结束的原因。
作为关于主题的快速文献来自here:
Ruby变量保存对象的引用和=运算符副本 参考文献。此外,实际上是自我分配,例如+ = b 翻译成a = a + b。因此,建议您注意 是否在某个操作中,您实际上是在创建一个新对象 或修改现有的。
例如,字符串&lt;&lt; “另一个”比字符串+ =“另一个”更快 (没有额外的对象创建),所以你最好使用任何 类定义的更新方法(如果这是你的意图),如果是的话 存在。但是,请注意所有其他变量的“副作用” 引用同一个对象:
a = 'aString'
c = a
a += ' modified using +='
puts c # -> "aString"
a = 'aString'
c = a
a << ' modified using <<'
puts c # -> "aString modified using <<"