【问题标题】:How does shovel (<<) operator work in Ruby Hashes?铲子 (<<) 运算符如何在 Ruby 哈希中工作?
【发布时间】:2012-03-09 18:19:36
【问题描述】:

当我在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 中的值实际上是教程所期望的。但我不明白使用&lt;&lt; 运算符和= 运算符有什么区别?

我的期望是:

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

谁能解释一下为什么我的期望是错误的?

【问题讨论】:

  • 有趣,这正是我所期望的。然后,山又只是山。

标签: ruby hash


【解决方案1】:

你把它的工作方式搞混了。首先,哈希没有&lt;&lt; 方法,您示例中的该方法存在于数组中。

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

当您执行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 关于#&lt;&lt; 方法以及您实际调用它的对象是什么。

【讨论】:

  • 知道了,谢谢。因此,原始的空数组是一个存储为默认值的对象。我们不断取回原来的对象而不是nil。整洁的!感谢这两个答案(你和@Gazler),都赞成,但接受了。
猜你喜欢
  • 1970-01-01
  • 2016-01-01
  • 2016-10-27
  • 2021-04-16
  • 1970-01-01
  • 2011-06-08
  • 1970-01-01
  • 2015-11-10
  • 2023-02-26
相关资源
最近更新 更多