请参见下面的示例
require "set"
s = [[1, 2], [3, 4]].to_set # s = {[1, 2], [3, 4]}
m = s.max_by {|a| a[0]} # m = [3, 4]
m[0] = 9 # m = [9, 4], s = {[1, 2], [9, 4]}
s.delete(m) # s = {[1, 2], [9, 4]} ?????这与数组的行为不同。(如果我们删除.to_set,我们将得到预期的s = [[1, 2]]。)这是一个bug吗?
发布于 2012-04-28 15:34:36
是的,这是一个bug,或者至少我会称它为bug。有些人会称这是“一个意外泄露给外界的实现细节”,但这只是一种花哨的城市男孩对bug的说法。
这个问题有两个主要原因:
其结果是,您在Hash不知道的情况下修改了内部Hash的键,这会使可怜的Hash变得不再真正知道它拥有什么键。哈希类有一个rehash method
重新散列hsh→
根据每个键的当前哈希值重新生成哈希。如果key对象的值在插入后发生了更改,此方法将重新索引hsh。
A= "a","b“c= "c","d”h={a => 100,c => 300 } ha #=> 100 a= "z“ha #=> nil h.rehash #=> {"z","b"=>100,"c","d"=>300} ha #=> 100
请注意rehash文档附带的示例中的有趣行为。散列使用键k的k.hash值来跟踪事物。如果您有一个数组作为键,并且您更改了数组,那么您也可以更改数组的哈希值;结果是hash仍然将该数组作为键,但不能找到该数组作为键,因为它将在存储桶中查找新的hash值,但该数组将在存储桶中查找旧的hash值。但是,如果你rehash散列,它将突然能够再次找到它的所有密钥,衰老消失了。对于非数组的键,也会出现类似的问题:你只需要改变键的哈希值,使其哈希值发生变化,包含该键的哈希值就会变得混乱,并在丢失时四处游荡,直到你rehash它为止。
Set class在内部使用散列来存储其成员,并将成员用作散列的键。所以,如果你改变了一个成员,集合将会变得混乱。如果Set有一个rehash方法,那么你可以通过用rehash把Set打在头上来解决这个问题;可惜,Set中没有这样的方法。然而,你可以在你自己的插件中添加:
class Set
def rehash
@hash.rehash
end
end然后,您可以更改密钥,在集合上调用rehash,您的delete (以及各种其他方法,如member?)将正常工作。
https://stackoverflow.com/questions/10361400
复制相似问题