はい、これはバグです。少なくとも私はバグと呼んでいます。これを「実装の詳細が誤って外の世界に漏れた」と呼ぶ人もいますが、それはバグのための空想的なズボンの都市少年の話です。
この問題には、次の 2 つの主な原因があります。
- Set が知らないうちに Set の要素を変更しています。
- 標準の Ruby Setはハッシュとして実装されています。
その結果、ハッシュがそれを認識せずに内部ハッシュのキーを変更しているため、貧弱なハッシュが混乱して、それがもはやどのキーを持っているのか本当にわからなくなります。Hash クラスには次のrehash
メソッドがあります。
再ハッシュ → hsh
各キーの現在のハッシュ値に基づいてハッシュを再構築します。挿入後にキー オブジェクトの値が変更された場合、このメソッドはhsh のインデックスを再作成します。
a = [ "a", "b" ]
c = [ "c", "d" ]
h = { a => 100, c => 300 }
h[a] #=> 100
a[0] = "z"
h[a] #=> nil
h.rehash #=> {["z", "b"]=>100, ["c", "d"]=>300}
h[a] #=> 100
rehash
ドキュメントに含まれている例の興味深い動作に注目してください。k.hash
ハッシュは、キーの値を使用して物事を追跡しますk
。キーとして配列があり、その配列を変更すると、配列のhash
値も変更できます。その結果、ハッシュはまだその配列をキーとして持っていますが、ハッシュはその配列をキーとして見つけることができませんhash
。古いhash
値。しかし、あなたrehash
がハッシュであれば、突然すべてのキーを再び見つけることができ、老化はなくなります. 非配列キーでも同様の問題が発生します。キーを変更する必要があるだけです。hash
値が変更され、そのキーを含むハッシュが混乱し、迷子になるまで迷子にrehash
なります。
Set クラスは内部的に Hash を使用してメンバーを格納し、メンバーはハッシュのキーとして使用されます。そのため、メンバーを変更すると、セットが混乱します。Set にrehash
方法があれば、Set の頭を逆さまに叩いて問題を回避することができますrehash
。残念ながら、Set にはそのようなメソッドはありません。ただし、次の場所で独自のモンキー パッチを適用できます。
class Set
def rehash
@hash.rehash
end
end
次に、キーを変更rehash
し、セットを呼び出すと、delete
(および などの他のさまざまなメソッドmember?
) が適切に機能します。