Rubyの配列の挙動でハマった

最近Ruby書いてる。文化が違って戸惑うことも多いけどRuby快適な感じする。ただ、配列でハマったので記録をのこしておく。

びっくりした例

a = Array.new(10,[]) #空の配列を10個持った配列を作る
4.times do
    a[0].push "hogehoge"
end

p a[0] # ["hogehoge", "hogehoge", "hogehoge", "hogehoge"] (予想通り)
p a[1] # ["hogehoge", "hogehoge", "hogehoge", "hogehoge"] (!?)

よくかんがえれば当然の話だった。

せつめい

Rubyの変数はオブジェクトの実態ではなくてオブジェクトへの参照を保持している。

つまり、以下はコメントが嘘で

a = Array.new(10,[]) #空の配列を10個持った配列を作る

ただしいコメントを書くならこんな感じ

a = Array.new(10,[]) #ひとつの空の配列への参照を10個作る

絵で書くとこう

たったひとつの[]に対してa[0]からa[9]が参照を持ってる状態。

なのでa[0]に対してそうさをするとa[1..9]にも影響がでる

解決策

こう書き換えた

a = []
0.upto(10) do |i|
   a[i] = []
end

かっこわるい感じするけどなんかほかにいい方法ないのだろうか。Rubyわからん