読者です 読者をやめる 読者になる 読者になる

nekoTheShadow’s diary

技術ブログとして始めたはずが、読書&愚痴ブログになりました(´・ω・`)

Array.newの見知らぬ仕様。

rubyのお勉強中、次のような配列がほしいとなりました。

[[true,  false, false, false],
 [false, false, false, false],
 [false, false, false, false],
 [false, false, false, false]]

正方形の左端だけがtrue、残りは全部falseというイメージ。

簡単そうですね。
ちゃっちゃと書いてしまいましょう。

ary = Array.new(4,Array.new(4,false))
ary[0][0] = true

できたできた……と満足していたのもつかの間、何かがおかしい。
いろいろ調べてみたところ、次のようなことがわかりました。

ary = Array.new(4,Array.new(4,false))
ary[0][0] = true
p ary
#=> [[true, false, false, false], 
#    [true, false, false, false], 
#    [true, false, false, false], 
#    [true, false, false, false]]

「何か、思っていたのと違う?」と思い、慌ててArrayのクラスメソッドnewの使い方を確認したところ、次のような記述を発見してしまったという次第です。

長さ size の配列を生成し、各要素を val で初期化して返します。
要素毎に val が複製されるわけではないことに注意してください。 全要素が同じオブジェクト val を参照します。

これは知りませんでした。
ちなみにほかの例でも同じようなことが起こります。

hashs = Array.new(4,Hash.new)
hashs[0][:name] = "nekoTheShadow"
p hashs

としたとき、一見すると次のような結果が得られるような気がします。

[{:name=>"nekoTheShadow"}, {}, {}, {}]

しかし、実際にはこうなるわけです。

[{:name=>"nekoTheShadow"}, 
 {:name=>"nekoTheShadow"}, 
 {:name=>"nekoTheShadow"}, 
 {:name=>"nekoTheShadow"}]

それにしても日々不勉強が明らかになりますね。
頑張らねば。