Hash の key の同一性の判定について
Ruby のハッシュ (連想配列) に関して。 ハッシュは以下のように生成することができます。
hash = { "key1" => "val1", "key2" => "val2" }
そして key を指定して value を得ることができるわけですが、そのときに問題となるのがどうやって key の同一性を判定しているのかどうか、です。例えば、String オブジェクトが 2 つあり、値として同一の場合。 このとき値は同一ですが、オブジェクトとしては同一ではありません。 ハッシュの key の同一性をどのようにして判定しているのかが重要になります。
str1 = "test"
str2 = "test"
# 値としては同一
p ( str1 == str2 ) ? true : false #=> true
# オブジェクトとしては同一ではない
p ( str1.equal? str2 ) ? true : false #=> false
Object#eql? メソッド
Ruby リファレンスマニュアルの Hash クラスに関するページ を見ると、以下のように書かれています。
ハッシュの格納に用いられるハッシュ値の計算には、Object#hash メソッド が使われ、キーの同一性判定には、Object#eql? メソッド が使われます。さらに Object#eql? メソッドについて見ると、
eql? のデフォルトの定義は equal? と同じくオブジェクトの同一性判定になっていると書かれています。 ということは String オブジェクトを key にすると、同じ値でもオブジェクトとしては別だから key として同一とみなされないのでは・・・? と思ってしまいます。
しかし
h = { "test" => "a", "test2" => "b" }
p h["test"] #=> "a"
として実行してみるとちゃんと key として同一として判定されていました。で、リファレンスマニュアルに書かれているとおりだとうまく同一判定されないはずなのに、なぜちゃんと同一だと判定されるのかについてちょっと調べてみました。 その結果 まつもとさんが書かれたこの文章中 に
それに合わせてというとちょっと違うと思いますが,eql? のデフォルトの定義は == をつかってという記述を発見しました。 デフォルトのままだと、Object#eql? メソッドはオブジェクトとしての同一性をみるのではなくて、値としての同一性を判定するみたいですね。こういう感じになっています.def eql?(other)
self == other
end
てことでリファレンスマニュアルの記述が古い、またはおかしいようです。