Ruby允许将一个可变对象用作哈希键,我很好奇当对象更新时它是如何工作的。如果引用的对象在更新时无法从关键请求中恢复,那么它似乎是无法恢复的。
key = [1,2]
test = {key => 12}
test # => {[1, 2] => 12}
test[key] # => 12
test[[1,2]] # => 12
test[[1,2,3]] # => nil
key << 3
test # => {[1, 2, 3] => 12}
test[key] # => nil
test[[1,2]] # => nil
test[[1,2,3]] # => nil
为什么这样做?为什么我不能为哈希提供一个键,它将返回与我原来用作键的列表相关的值?
答案 0 :(得分:2)
当两个对象的哈希值相同且两个对象是eql时,它们引用相同的哈希键?彼此。
变换键不会改变它存储的哈希值。变异后,尝试使用[1,2]
进行索引与hash
匹配但不匹配eql?
,而[1,2,3]
与eql?
匹配,但hash
找不到test
。 {1}}。
请参阅this article以获得更详细的解释。
但是,您可以重新计算test.rehash
test[[1,2,3]] # => 12
,以根据当前键值重新计算哈希值:
{{1}}
答案 1 :(得分:2)
class D
end
p D.new.methods.include?(:hash) #=> true
# so the D instance has a hash method. What does it do?
p D.new.hash #=> -332308361 # just some number
(几乎)Ruby中的每个对象都有hash
方法。当对象用作键时,Hash调用此方法,并使用结果数来存储和检索键。 (有处理重复数字的智能程序(哈希冲突))。检索是这样的:
a_hash[[1,2,3]]
# the a_hash calls the hash method to the [1,2,3] object
# and checks if it has stored a value for the resulting number.
此编号仅创建一次:将密钥添加到哈希实例时。
在将密钥包含在散列中之后开始弄乱密钥时出现问题:对象的hash
方法将与散列中存储的方法不同。
记得要及时做到:
a_hash.rehash
将重新计算所有哈希值。
注意:对于字符串键,副本用于计算哈希值,因此修改原始键无关紧要。
答案 2 :(得分:1)
如果数组的标识作为散列键很重要,那将是不方便的。如果您使用密钥[1, 2]
的哈希,则希望能够使用具有相同内容的其他数组对象[1, 2]
来访问该哈希。您希望通过内容进行访问,而不是身份。这意味着将特定对象(具有特定对象id)存储为密钥对于散列无关紧要。重要的是在分配给哈希时密钥的内容。
因此,在执行key << 3
后,test[key]
或test[[1, 2, 3]]
不再返回存储的值是有意义的,因为key
在分配给{{1}时} test
。
棘手的是[1, 2]
也会返回test[[1, 2]]
。这是Ruby的限制。
如果您希望哈希反映在关键对象中所做的更改,则有一个方法nil
。
Hash#rehash