如果您使用Hash.new 的块形式创建Hash,则每次您尝试访问实际不存在的元素时都会执行该块。所以,让我们看看会发生什么:
h = Hash.new { [] }
h[0] << 'a'
这里首先要评估的是表达式
h[0]
当它被评估时会发生什么?好了,块开始运行:
[]
这不是很令人兴奋:该块只是创建一个空数组并返回它。它不做任何其他事情。特别是,它不会以任何方式改变h:h 仍然是空的。
接下来,带有一个参数'a' 的消息<< 被发送到h[0] 的结果,这是块的结果,它只是一个空数组:
[] << 'a'
这是做什么的?它将元素 'a' 添加到一个空数组中,但由于该数组实际上并未分配给任何变量,因此它会立即被垃圾回收并消失。
现在,如果您再次评估 h[0]:
h[0] # => []
h 仍然为空,因为没有分配给它,因此密钥 0 仍然不存在,这意味着该块将再次运行再次,这意味着它再次返回一个空数组(但请注意,它现在是一个全新的、不同空数组)。
h[0] += ['a']
这里发生了什么?首先,运算符 assign 被脱糖为
h[0] = h[0] + ['a']
现在,右侧一侧的h[0] 得到评估。它返回什么?我们已经讨论过这个:h[0] 不存在,因此该块开始运行,该块返回一个空数组。同样,这是一个全新的 third 空数组。这个空数组被发送了带有参数['a'] 的消息+,这导致它返回另一个新数组,即数组['a']。然后将该数组分配给h[0]。
最后,在这一点上:
h[0] # => ['a']
现在你终于在h[0]中添加了一些东西,所以很明显,你取出了你输入的东西。
所以,要回答您可能提出的问题,为什么不拿出您输入的内容呢?你没有一开始就放任何东西!
如果你真的想分配到块内的哈希,你必须,很好地分配到块内的哈希:
h = Hash.new {|this_hash, nonexistent_key| this_hash[nonexistent_key] = [] }
h[0] << 'a'
h[0] # => ['a']
如果您查看所涉及对象的身份,实际上很容易看出代码示例中发生了什么。然后可以看到每次调用h[0],都会得到一个不同的数组。