我想使用相同的键但不同的值复制哈希。我编写了以下代码片段,并遇到了一些我没想到的事情:
hsh = {:foo => 'foo', :bar => 'bar'}
hsh_copy = Hash[hsh.keys.zip([[]] * hsh.length)] # => {:foo=>[], :bar=>[]}
hsh_copy[:foo] << 1
hsh_copy[:bar] << 2
hsh_copy # => {:foo=>[1, 2], :bar=>[1, 2]}
似乎不是在使用*
运算符时复制嵌套数组,而是继续引用第一个数组。
如果有人能解释为什么这种情况发生,我会很高兴。此外,我们还会感谢更好的复制哈希的方法,但我更关心的是理解为什么*
在这里没有按预期工作。
答案 0 :(得分:3)
如果Array#*
复制了数组的元素,那么当在具有不可复制元素(其中包括数字)的数组上使用时,它会中断,这是不可取的。
至于如何做你想做的事:用hsh.keys.zip([[]] * hsh.length)
替换hsh.map {|k,v| [k, []] }
。
答案 1 :(得分:1)
*
运算符将数组的副本连接在一起以满足新的长度。
如果一个数组元素引用一个对象,当它被复制时,实际上会创建一个新的数组元素,但它是一个引用同一个对象的新数组元素。
例如:
irb(main):012:0> ([[]] * 3).map { |e| e.object_id }
=&GT; [2149128060,2149128060,2149128060]
在您的情况下,您可以使用.map
创建新元素,并让Ruby每次都使用[]创建一个新对象,但对于一般解决方案,请从以下开始:
irb(main):013:0> ([[]] * 3).map { |e| e.clone.object_id }
=&GT; [2149106700,2149106660,2149106640]