我正在向一个哈希键添加项目。 我期望得到的结构应该像这样:
{
'a' : [1],
'b' : [2, 3, 4]
}
我使用数组来初始化哈希表。
irb> hash = Hash.new([])
=> {}
然后开始使用它:
irb> hash['a'] << 1
=> [1]
irb> hash['b'] << 2
=> [1, 2]
但事实证明:
irb> hash
=> {}
可以尝试使用以下方法:
hash = Hash.new{|h, k| h[k] = []}
hash['a'] << 1 # => [1]
hash['b'] << 2 # => [2]
你得到意外结果的原因是你指定了一个空数组作为默认值,但是使用的是同一个数组;没有进行复制。正确的方法是使用一个新的空数组来初始化值,就像我的代码中那样。
a = b = 'foo'; a.replace 'bar'; b # => 'bar'
- Marc-André LafortuneHash.new([])
时,它使用相同的数组对象,但是当你执行 Hash.new("string")
时,它并没有使用相同的字符串,这让我感到很奇怪。 - Automaticoh = Hash.new("don't do this"); h[0].upcase!; h[1] # => "DON'T DO THIS"
- Marc-André Lafortuneh = Hash.new("W"); h["test"] = "data"; p h["a"] #=> "W"
。我猜它只重新分配了 h["test"]
对象,而没有实际更改对象。 - Automatico[]
作为默认值存储在访问未知键时返回。由于Array#<<
直接修改其接收器,因此这个最初为空的数组会增长。hash['a'] << 1
时,发生以下情况:
hash
查看是否有名为'a'
的键Hash.new([])
构造它,所以它确实有这样一个值[]
并返回它。[] << 1
,这意味着哈希现在存储[1]
作为请求先前未遇到的键时返回的值。hash = Hash.new{|h, key| h[key] = []}
hash['a'] << 1
和 hash['b'] << 2
不是创建键/值对的正确语法。你必须使用=
:
hash['a'] = []
hash['a'] << 1
hash['b'] = []
hash['b'] << 2
这将为您提供哈希值 {'a' : [1], 'b' : [2]}
这正是你所期望看到的行为。
你从未向Hash
中添加任何内容,因此Hash
完全为空。当你查找一个键时,该键永远不存在,因此返回默认值,你已指定为一个Array
。
所以,你查找不存在的键'a'
,因此返回你指定的Array
作为默认值。然后,你在该Array
上调用<<
,将一个值(1
)附加到它上面。
接下来,你查找不存在的键'b'
,因此返回你指定的Array
作为默认值,该数组现在包含了你之前添加的元素1
。然后,你在该Array
上调用<<
,将值2
附加到它上面。
你最终得到的是一个仍然为空的Hash
,因为你从未向其中添加任何内容。现在Hash
的默认值是包含值1
和2
的数组。
你看到的输出是因为IRb总是打印出最后评估的表达式的结果。你示例中的最后一个表达式是在Array
上调用<<
。 <<
返回其接收器,这就是整个表达式的返回值,因此是IRb打印出的内容。