不変キーは、そのハッシュコードが安定するため一般的に意味があります。文字列はMRIコードのこの部分では、特別に変換される理由
これは:文字列キー場合、一言で言えば
if (RHASH(hash)->ntbl->type == &identhash || rb_obj_class(key) != rb_cString) {
st_insert(RHASH(hash)->ntbl, key, val);
}
else {
st_insert2(RHASH(hash)->ntbl, key, val, copy_str_key);
}
、st_insert2
トリガする関数へのポインタが渡されます。 dupとfreeze。
我々は理論的にはハッシュキーとして不変のリストと不変のハッシュをサポートしたいのであれば、我々はこのような何かにそのコードを修正することができます:
freeze_obj
のように定義されるだろう
VALUE key_klass;
key_klass = rb_obj_class(key);
if (key_klass == rb_cArray || key_klass == rb_cHash) {
st_insert2(RHASH(hash)->ntbl, key, val, freeze_obj);
}
else if (key_klass == rb_cString) {
st_insert2(RHASH(hash)->ntbl, key, val, copy_str_key);
}
else {
st_insert(RHASH(hash)->ntbl, key, val);
}
:
static st_data_t
freeze_obj(st_data_t obj)
{
return (st_data_t)rb_obj_freeze((VALUE) obj);
}
これは、アレイキーが変更可能であった特定の不一致を解決します。しかし、実際に一貫するためには、より多くの種類のオブジェクトを不変にする必要があります。
なしすべてタイプです。たとえば、Fixnumのような即時オブジェクトをフリーズする必要はありません。なぜなら、事実上、各整数値に対応するFixnumのインスタンスが1つしかないからです。このため、Fixnum
とSymbol
ではなく、String
のみ特殊なケースにする必要があります。
文字列が非常によくハッシュキーとして使用されるため、文字列はRubyプログラマーの便宜のための特別な例外です。
逆に、他のオブジェクトタイプが明らかに矛盾した行動につながる、このようないを凍結していることの理由は、主にエッジケースをサポートしないようにマッツ&会社の都合です。実際には、比較的少数の人々が配列やハッシュのようなコンテナオブジェクトをハッシュキーとして使用します。あなたがそうするならば、挿入する前に凍結するのはあなた次第です。
非即時オブジェクトをフリーズする動作は、すべてのオブジェクトに存在するbasic.flags
ビットフィールドのFL_FREEZE
ビットを反転するだけのため、これはパフォーマンスに関するものではありません。それはもちろん安い操作です。
また、パフォーマンスについては、コードのパフォーマンスに重大な部分にある文字列キーを使用する場合は、挿入を行う前に文字列をフリーズすることをお勧めします。そうしないと、dupがトリガーされ、これはより高価な操作です。
更新 @sawaは、単に凍結残して、あなたの配列、キーは元の配列はまた、(不愉快な驚き可能性があり、キーの使用状況、予想外不変外であるかもしれない意味していることを指摘し、それはあなたを右役立つであろう大藤が、配列をハッシュ・キーとして使用する場合)。したがって、dup + freezeがその抜け道であると推測すれば、実際には顕著なパフォーマンスコストが発生します。三番目の手で、それを完全に凍らせないでおくと、あなたはOPのオリジナルの奇妙さを得る。周りの奇妙さMatzらがこれらのエッジケースをプログラマに遅らせるもう一つの理由。
私の目的のために、私ができる最高のものは 'h.keys.each {| s | h.store(s.downcase、h.delete(s))} '。 – sawa
私は "なぜ"を推測できますか?文字列は配列よりも一般的なユースケースであるだけでなく、文字列のフリーズは実装が簡単であると思われます。私がPerlを知っていたら、RubyがPerlのハッシュ・ビヘイビアで一貫しているかどうかを見ていきたいと思います。もし私が日本語に堪能だったなら、キーのフリーズが実行されたことを見て、それがバグ報告やメーリングリストの議論の結果であるかどうかを見てみましょう。 –
@AndrewGrimm [Here](http://doc.ruby-lang.org/ja/1.9.2/class/Hash.html)は、配列とハッシュは、変更が可能であるため、ハッシュのための良いキーを作るのではなく、文字列がフリーズされるので、再ハッシュを呼び出す必要はありません。 steenslagの答えと一貫しています。 – sawa