RubyのHashの落とし穴?


Rubyの配列とHashを使っていて個人的にハマったのでメモ。
Hashの配列を作り、それをHashで扱うときがありましたが、Array.newで初期化してから値の変更をしようとすると全てのkeyの値が変わってしまいました。

# これはダメ
temp = {}
init = {:a => 0, :b => 0}
temp[:aaa] = Array.new(2, init)

p temp

# 値を代入
temp[:aaa][0][:a] = 1

p temp






# これはOK
temp = {}
temp[:aaa] = [
  {
    :a => 0,
    :b => 0
  },
  {
    :a => 0,
    :b => 0
  }
]

p temp

# 値を代入
temp[:aaa][0][:a] = 1

p temp

結果

{:aaa=>[{:a=>0, :b=>0}, {:a=>0, :b=>0}]}
{:aaa=>[{:a=>1, :b=>0}, {:a=>1, :b=>0}]}
{:aaa=>[{:a=>0, :b=>0}, {:a=>0, :b=>0}]}
{:aaa=>[{:a=>1, :b=>0}, {:a=>0, :b=>0}]}

(追記)
原因はこれ。
http://simanman.hatenablog.com/entry/2013/06/24/200306
初期化の仕方に問題があるみたいです。
最初の初期化で別々の配列オブジェクトを定義したつもりが、実は全て同じ配列オブジェクトを参照しているらしいですね。

ちなみに
temp[:aaa] = Array.new(2, init)
ここの部分ですが、
temp[:aaa] = Array.new(2).map{Hash.new}
のように初期化しないとダメでした。