Rubyのライブラリを読んでいるとHashの初期化で
h = Hash.new([].freeze)というのを良く見かける。
これはどういう意味なんだろうと調べてみた。
まずは freeze の意味 Object - Rubyリファレンスマニュアル
オブジェクトの内容の変更を禁止します。self を返します。 フリーズされたオブジェクトの変更は例外 TypeError を発生させます。という事で、任意のオブジェクトを変更不可能にできます。
次に、Hash.new の引数の意味 Hash - Rubyリファレンスマニュアル
Hash.new([ifnone]) 空の新しいハッシュを生成します。 ifnone はキーに対応する値が存在しない時のデフォルト値です。 デフォルト値の扱いには注意が必要です。 ( trap::Hash )。
という事で、Hashオブジェクトに対して存在しないキーを要求したときに返す値をコンストラクタで指定できるらしい。
例)
h = Hash.new(4) age = h[:age] # => 4つまり、 Hash.new([].freeze)となっているのは、 デフォルト値を[](空配列)とし、さらにそれを 変更されては困る場合の宣言の仕方だった。 しかしこれにはtrap::Hash にもあるように、freezeを付けないと、 デフォルト値自体に破壊的な操作をすると、 混乱するから気をつけよう。と書いてあり、 その破壊的な操作の殆どは予期せず行ってしまうだろう事を 懸念している。
例)
h = Hash.new([]) # key=0の値に0を追加 h[0] << 0 # key1の値に1を追加 h[1] << 1 # 間違った期待 p h #=> {0=>[0], 1=>[1]} # 実際の値 p h #=> {} p h.default #=> [0, 1]どうやら、freezeは上記の混乱を避ける事にも役立っている。
そういう意味だったのかぁ。。 やっと理解できました。
その他まとめ Hashオブジェクトの初期化- Hash.new() キーが無い場合はnil
- Hash.new( obj ) キーが無い場合はobj
- Hash.new( ブロック ) ブロックの結果を返す ex) Hash.new( | hash, key | hash[key] = "Booo!" ) 2.を使う場合は要注意 で特に値を変更するような場合は、 誤ってアクセスした時に気がつかない場合があるので、 freezeを使う。 でも個人的には、freezeを使うくらいなら、 1を採用してnilを返すようになっていれば良いと思うのだが。。 freezeにする必要があるケースを強引に考えると、 基本的に特定の範囲のキーを期待するが、 将来的に期待外のキーが与えられる可能性があり、 そのキーを拒否する事もするべきでないようなケース。。。 どんなケースだろう。