-- / --
--
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

12 / 25
Wed

「with」 を打とうとすると 「width」 になってる Ziphil です。

Ruby でハッシュを使っていたら、 予期しない出来事に遭遇したので、 それについてまとめてみましたよー。

とりあえず、 まずは Hash クラスのコンストラクタを使って、 デフォルト値が空のハッシュになるような、 ハッシュ hash1 を作成します。 で、 値を設定します。 こんなコードを書きました。

hash1 = Hash.new{{}}
hash1[0][:a] = 100

さて、 ここで問題です! このとき、 hash1[0][:a] の返り値は何でしょう? え、 そんなの当たり前じゃないかって?

p hash1[0][:a]  #=> nil

答えは nil です。 あれ?

じゃ、 続いて次の問題にいきますよー! 同じようにハッシュ hash2 を定義して、 値を設定します。

hash2 = Hash.new({})
hash2[0][:a] = 100

このとき、 hash2[0][:a] の返り値は何でしょう? 今度こそ間違えないですよね・・・?

p hash2[0][:a]  #=> 100

答えは 100 でした! あれれ?

じゃ、 続いて続いて問題! またまた同じようにハッシュ hash3 を定義して、 値を設定します。

hash3 = Hash.new{|h, k| h[k] = {}}
hash3[0][:a] = 100

何が聞かれるか分かってると思いますが、 hash3[0][:a] の返り値は何でしょう? 大丈夫ですよね?

p hash3[0][:a]  #=> 100

答えは 100 でした! あれれれ?

混乱しちゃいましたか? じゃ、 別のキーに対する値を取得しようとしたらどうなるでしょうか? 例えば、 hash1[1][:a]hash2[1][:a]hash3[1][:a] それぞれの返り値は?

p hash1[1][:a]  #=> nil
p hash2[1][:a]  #=> 100
p hash3[1][:a]  #=> nil

さて、 そろそろ解説しましょうか。

ブロックを使わない Hash の定義 (hash2) では、 デフォルト値として、 常に同一のオブジェクトが返されます。 オブジェクト ID を調べてみれば一目瞭然です。

p hash2[0].object_id  #=> 10730174
p hash2[1].object_id  #=> 10730174

一方、 ブロックを使う Hash の定義 (hash1) では、 存在しないキーに対する値を呼び出そうとするたびに、 ブロックが実行されます。 そのため、 値が ([]= メソッドとか store メソッドとかで) 直接設定されない限り、 同じキーを指定しても、 異なるオブジェクトが返ってきます。

p hash1[0].object_id  #=> 10238340
p hash1[1].object_id  #=> 10238256
p hash1[0].object_id  #=> 10238200

したがって、 hash2[0][:a] = 100 は、 hash2 のデフォルト値のオブジェクトそのものを書き換えてしまっているため、 それ以降、 存在しないキーの値を取得しようとすると、 書き換えられた後のオブジェクトが返ってきてしまい、 hash2[1][:a] の結果も 100 になります。 一方、 hash1[0][:a] = 100 は、 ブロックを実行するときに生成された空のハッシュにキーと値を設定しているだけなので、 次に hash1[0] を実行しても、 ブロックの実行結果である空のハッシュが返され、 hash1[0][:a] の結果は nil になるわけです。

さて、 それをふまえて hash3 のような定義について考えてみましょう。 これに対して存在しないキーの値を取得しようとすると、 ブロックが実行されます。 ブロック内では、 自分自身にキーと値を設定しています。 また、 Hash#[]= メソッド や Hash#store メソッドの返り値は、 設定された値そのものになっています。 つまり、 hash3[0] が呼ばれた時点で、 hash3 のキー 0 に対して空のハッシュが格納され、 同時に hash3[0] の結果として、 同一オブジェクトの空のハッシュが返されます。 そして、 その空のハッシュに対し、 キー :a と値 100 を設定しているわけです。 オブジェクト ID を調べてみれば、 さらに理解できると思います。

p hash3[0].object_id  #=> 10696952
p hash3[1].object_id  #=> 10696868
p hash3[0].object_id  #=> 10696952
p hash3[1].object_id  #=> 10696868

まあ、 要するに、 ハッシュとか配列のデフォルト値の設定には、 十分注意しましょうということです。 特に、 デフォルト値に対し破壊的なメソッドを実行する場合は、 hash3 みたいな定義の仕方をしないと痛い目にあいます。

スポンサーサイト

comment ×0
コメント
管理者にだけ表示を許可する
 
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。