2010-12-20 77 views
3

我想使用相同的鍵但不同的值複製散列。我編寫了下面的代碼片段,和遇到的事情我沒想到:爲什麼Array *在Ruby中引用和不復制值?

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]} 

看來,而不是使用*操作時複製嵌套的數組,它只是繼續引用第一個數組。

如果有人能解釋我會很高興爲什麼這種情況正在發生。此外,更好的方法來複制哈希將不勝感激,但我更關心理解爲什麼*不按預期在這裏工作。

回答

3

如果Array#*複製了數組的元素,它將在具有不可複製元素(其中包括數字)的數組上使用時中斷,這是不可取的。

至於如何做你想做的事:用hsh.map {|k,v| [k, []] }替換hsh.keys.zip([[]] * hsh.length)

+0

感謝您的回答 - 看起來ruby文檔有些誤導,因爲它明確地寫着「副本」。儘管如此,爲什麼下面的代碼不會用'['d']'替換所有'['a']',而不僅僅是第一個? 'arr = [['a'],['b'],['c']] * 3; arr [0] = ['d']'。然後這個:'arr = [[],[],[]] * 3; arr [0] = {}'? – vonconrad 2010-12-20 00:31:16

+0

@vonconrad:因爲在這些情況下,你並沒有改變第一個數組元素,所以你正在設置一個新的數組元素。這就是爲什麼'a =「a」的原因。 b = a; b.replace(「b」)'同時改變'a'和'b',而'a =「a」; b = a; b =「b」'不。 – sepp2k 2010-12-20 00:35:28

+0

哎呀。非常感謝! – vonconrad 2010-12-20 00:45:56

1

*運算符將數組的副本連接在一起以滿足新的長度。

如果一個數組元素引用一個對象,當它被複制時,實際上會創建一個新的數組元素,但它是一個引用同一對象的新數組元素。

例如:

irb(main):012:0> ([[]] * 3).map { |e| e.object_id } 

=>【2149128060,2149128060,2149128060]

在你的情況,你可以只創建新的元素與.map,讓紅寶石與[]每一個新的對象時間,但對於一般的溶液,開始:

irb(main):013:0> ([[]] * 3).map { |e| e.clone.object_id } 

=> [2149106700,2149106660,2149106640]

相關問題