如何在Ruby Hashes中使用铲(<<<

时间:2012-02-18 18:00:17

标签: ruby hash

当我在about_hashes.rb

中发现这件事时,我正在经历Ruby Koans tutorial series
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]将为[]

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

2 个答案:

答案 0 :(得分:64)

你混淆了这种方式。首先,Hash没有<<方法,示例中的方法存在于数组中。

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

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

答案 1 :(得分:57)

当您执行hash = Hash.new([])时,您正在创建一个哈希值,其默认值是所有键的完全相同的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关于#<<方法以及您实际调用的对象的说法。