我将粘贴一个我尝试的简单示例,以便那些阅读此内容的人会清楚。
irb(main):001:0> h = { }
=> {}
irb(main):002:0> a=[1,2,3]
=> [1, 2, 3]
irb(main):003:0> a.object_id
=> 69922343540500
irb(main):004:0> h[a] = 12 #Hash with the array as a key
=> 12
irb(main):005:0> a << 4 #Modified the array
=> [1, 2, 3, 4]
irb(main):006:0> a.object_id #Object id obviously remains the same.
=> 69922343540500
irb(main):007:0> h[a] #Hash with the same object_id now returns nil.
=> nil
irb(main):008:0> h #Modified hash
=> {[1, 2, 3, 4]=>12}
irb(main):009:0> h[[1,2,3,4]] #Tried to access the value with the modified key -
=> nil
irb(main):011:0> h.each { |key,value| puts "#{key.inspect} maps #{value}" }
[1, 2, 3, 4] maps 12
=> {[1, 2, 3, 4]=>12}
现在,当我遍历哈希时,可以识别密钥和值之间的映射。
有人可以解释一下ruby hash的这种行为以及散列键的属性是什么。
1)正如我上面提到的,object_id没有改变 - 那么为什么值设置为nil。
2)是否有任何可能的方法,以便我可以从散列'h'返回值'12',因为上面提到的h [[1,2,3,4]]返回nil。
答案 0 :(得分:8)
这是因为密钥在使用时不应更改其值。如果值发生变化,我们应该根据其当前值重建哈希值。查看Ruby API rehash
方法。您可以通过在更改密钥后重新重新生成哈希来获取值,如下所示:
irb(main):022:0> h.rehash
=> {[1, 2, 3, 4]=>12}
irb(main):023:0> h[a]
=> 12
答案 1 :(得分:1)
使用#eql?
方法检查哈希键,由于[1, 2, 3]
不是.eql?
到[1, 2, 3,4]
,因此哈希查找的结果会有所不同。
如果语义不适合你,也许你想使用Array
之外的其他内容作为Hash
密钥?
答案 2 :(得分:1)
ruby hash api提供了答案:密钥在用作密钥时不应更改其值。
我猜实习生为a
计算哈希并用于快速查找(因为密钥不应该改变,哈希总是相同的)。所以,当你执行h[a]
时,它找不到匹配项([1,2,3] .hash!= [1,2,3,4] .hash),当你执行h[[1,2,3]]
时哈希匹配,但对象不匹配([1,2,3]!= [1,2,3,4])。
修复是使用object_id作为键,因为它不会更改,h[a.object_id] = 12
将在更改时返回12。当然,这有一个缺点,即h[[1,2,3].object_id]
不会返回12。
答案 3 :(得分:1)
Stefaan Colman的答案更为彻底,但有几点意见:
Ruby使用Object#hash方法来散列对象。
此时您可以像a.delete(4); h[a]
一样退出,[1,2,3]
也可以再次用作关键字。