2012-02-18 66 views
45

我所經歷的Ruby Koans tutorial series,當我在about_hashes.rb臨到這一點:shovel(<<)運算符在Ruby Hashes中如何工作?

def test_default_value_is_the_same_object 
    hash = Hash.new([]) 

    hash[:one] << "uno" 
    hash[:two] << "dos" 

    assert_equal ["uno", "dos"], hash[:one] 
    assert_equal ["uno", "dos"], hash[:two] 
    assert_equal ["uno", "dos"], hash[:three] 

    assert_equal true, hash[:one].object_id == hash[:two].object_id 
end 

值在assert_equals,實際上是預期的教程。但我不明白如何使用<<運營商和=運營商有什麼區別?

我的期望是:

  • hash[:one]["uno"]
  • hash[:two]["dos"]
  • hash[:three][]

是否有人可以解釋爲什麼我的期望是錯誤的?

+4

有趣,這正是我的預期。然後,山再次只是山。 – 2013-03-03 07:19:17

回答

52

當你在做hash = Hash.new([])你正在創建一個哈希,其默認值是所有鍵完全相同的數組實例。所以,只要你訪問一個不存在的密鑰,你就會得到相同的數組。

h = Hash.new([]) 
h[:foo].object_id # => 12215540 
h[:bar].object_id # => 12215540 

如果你想每個鍵一個數組,你必須使用的Hash.new塊語法:

h = Hash.new { |h, k| h[k] = [] } 
h[:foo].object_id # => 7791280 
h[:bar].object_id # => 7790760 

編輯:還看什麼Gazler有關於#<<法說和你究竟在調用什麼對象。

+1

+1使用object_id來顯示引用。 – Gazler 2012-02-18 18:09:16

+0

感謝。因此,原始的空數組是一個存儲爲默認值的對象。我們一直在找回原來的對象而不是'nil'。整齊!感謝這兩個答案(由你和@Gazler),兩者都贊同,但接受這一點。 – bits 2012-02-18 18:12:38

58

你混淆了這個工作的方式。首先,哈希沒有<<方法,您的示例中的該方法存在於數組中。

您的代碼沒有錯誤的原因是因爲您通過構造函數將默認值傳遞給您的散列。 http://ruby-doc.org/core-1.9.3/Hash.html#method-c-new

hash = Hash.new([]) 

這意味着,如果一個項不存在,則它將返回一個數組。如果你運行下面的代碼:

hash = {} 
hash[:one] << "uno" 

然後你會得到一個未定義的方法錯誤。

所以,在你的榜樣,什麼是真正發生的事情是:

hash = Hash.new([]) 

hash[:one] << "uno" #hash[:one] does not exist so return an array and push "uno" 
hash[:two] << "dos" #hash[:two] does not exist, so return the array ["uno"] and push "dos" 

它不會返回每正如你所期待的時間一個元素的數組究其原因,是因爲它存儲的值的引用你傳遞給構造函數。這意味着每次按下某個元素時,都會修改初始數組。

+2

謝謝@gazler。這有助於說清楚。 – bits 2012-02-18 18:15:45

+1

多謝先生 – Etch 2012-12-05 22:18:06

+4

這應該是被接受的答案。更清楚的解釋。謝謝 – 2014-11-30 01:18:31