为什么将字符串铲入哈希会导致此结果?

我正在研究Ruby Koans,以便更好地掌握Ruby和TDD。 我在about_hashes.rb的代码中得到了第93 about_hashes.rb ,这让我感到困惑的是如何将它铲入默认构造函数而不是哈希值。 出于好奇,我尝试使用与字符串相同的东西作为构造函数的参数,它产生了类似的结果。

现在我的问题是,为什么,无论我使用什么密钥,都会检索相同的对象,以及如何在方法 test_default_value_is_the_same_object 中的哈希中的特定键中将新对象铲入数组

 def test_default_value_is_the_same_object hash = Hash.new([]) hash[:one] << "uno" hash[:two] << "dos" assert_equal ["uno", "dos"], hash[:one] #why not ["uno"]? assert_equal ["uno", "dos"], hash[:two] #why not ["dos"]? assert_equal ["uno", "dos"], hash[:three] #why not []? assert_equal true, hash[:one].object_id == hash[:two].object_id end def test_default_value_with_block hash = Hash.new {|hash, key| hash[key] = [] } hash[:one] << "uno" hash[:two] << "dos" assert_equal ["uno"], hash[:one] assert_equal ["dos"], hash[:two] assert_equal [], hash[:three] end 

关于原因的提示是以测试的名义。

test_default_value_is_the_same_object用于显示当您要求hash[:some_value_that_doesnt_exist_yet] ,默认情况下,您将返回您指定的默认值 – 每次都是相同的对象 。 通过修改该对象,可以为每个不存在的键修改它。 修改hash[:one]也会修改hash[:two]

test_default_value_with_block显示使用块构造哈希,该块将用于为每个键提供新值。 当你这样做时, hash[:one]hash[:two]是不同的。

当密钥不存在时,您已创建一个新的Hash ,其中Array作为累加器

 hash = Hash.new([]) hash[:one] << "uno" hash[:one] == ["uno"] #=> true 

 hash[:two] << "dos" (hash[:one] == hash[:two]) && (hash[:two] == ["uno","dos"]) #=> true hash[:three] == ["uno","dos"] #=> true 

因为["uno","dos"]是用Hash创建的原始数组,并且hash[:non_existant_key]指向它。

注意:在这种情况下,实际上没有向hash添加hash 。 它会类似于

  a = [] hash = {} hash.fetch(:one,a) << 'uno' hash.fetch(:two,a) << 'dos' hash.fetch(:three, a) #=> ['uno','dos'] hash #=> {} 

要解决此问题,您可以使用第二个测试中提到的语法

 hash = Hash.new {|h,k| h[k] = [] } 

这意味着每个新密钥都会将新Array实例化为其值,而不是一遍又一遍地重复使用相同的Array

obj是一个可变对象时,这就是Hash.new(obj)语法的问题