Array.newでハマりかける

二次元配列が必要になったのでこんな感じで作成する。

irb(main):001:0> x = Array.new(3,Array.new(3, 0))
=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

(0,1)-成分に値を代入する

irb(main):002:0> x[0][1] = 1
=> 1

(0,1)-成分だけ変えたはずなのに、(i,1)-成分が全て1になってしまっている

irb(main):003:0> x
=> [[0, 1, 0], [0, 1, 0], [0, 1, 0]]

なんでこうなるのかしばらく気づかなかった。ちなみにこう作成すれば問題ない

irb(main):004:0> x = Array.new(3) { Array.new(3, 0) }
=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
irb(main):005:0> x[0][1] = 1
=> 1
irb(main):006:0> x
=> [[0, 1, 0], [0, 0, 0], [0, 0, 0]]

要はArray.new(size, val)だと配列の各要素にvalの参照が渡されるので、外側のArray.newを呼び出したときの一度だけ内側のArray.new(3, 0)が実行されて、各要素にはそのとき生成された全く同じオブジェクトへの参照が渡されることになる。同じオブジェクトの値を変えたので、全ての列が同時に値を変えたように見えたわけだ。

後者だと各要素毎にArray.new(3, 0)が実行されてそれぞれ別のオブジェクトになるから、一つの成分の値だけ変えても当然他の列には影響を及ぼさない。

参照渡しと値渡しがよく分かってないのがバレバレだな…。ちなみに内側のArray.new(3,0)の0はリテラルだから参照渡しにはならず、代入しても他の行に影響を及ぼすことはない…でよかったはず。

カテゴリー: Program. タグ: . Array.newでハマりかける はコメントを受け付けていません。
%d人のブロガーが「いいね」をつけました。