铲运算符(<<)在Ruby Hashes中是如何工作的?

我正在阅读Ruby Koans教程系列 ,当我在about_hashes.rbabout_hashes.rb这个教程时:

 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]将是[]

有人能解释为什么我的期望错了吗?

当你在做hash = Hash.new([])你正在创build一个Hash,它的默认值是所有键完全相同的Array实例。 所以,只要你访问一个不存在的密钥,你就会得到相同的数组。

 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关于#<<方法以及您实际调用它的对象。

你混淆了这个工作的方式。 首先,一个哈希没有<<方法,在你的例子中的方法存在于数组中。

你的代码没有错误的原因是因为你通过构造函数将默认值传递给你的哈希。 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" 

它不会每次都返回一个数组,因为它会存储对构造函数传递的值的引用。 这意味着每次元素被按下时,它都会修改初始数组。