Rubyのオブジェクト配列

まずは,このRubyのプログラムをみてください.

class Abc
  attr_accessor :value
end

a = Array.new(5, Abc.new)

for i in 0..4
  a[i].value = i * 10
  puts a[i].value
end

puts "---"

for i in 0..4
  puts a[i].value
end

実行結果はこうなります.

$ ruby test.rb
0
10
20
30
40
---
40
40
40
40
40

期待していた結果,つまり後半のputsも,「0, 10, 20, 30, 40」という出力になると思っていましたが違うようです.

さて,なぜでしょう.

9行目と15行目の「puts a[i].value」を「p a[i]」に変えて,それぞれのオブジェクトID等中身を見てみます.

$ ruby test.rb
#<Abc:0x007faa6888e7c0 @value=0>
#<Abc:0x007faa6888e7c0 @value=10>
#<Abc:0x007faa6888e7c0 @value=20>
#<Abc:0x007faa6888e7c0 @value=30>
#<Abc:0x007faa6888e7c0 @value=40>
---
#<Abc:0x007faa6888e7c0 @value=40>
#<Abc:0x007faa6888e7c0 @value=40>
#<Abc:0x007faa6888e7c0 @value=40>
#<Abc:0x007faa6888e7c0 @value=40>
#<Abc:0x007faa6888e7c0 @value=40>

この結果を見る限り,「a[0], a[1], a[2], a[3], a[4]」は全て同じインスタンスのようです.

配列の初期化の部分

a = Array.new(5, Abc.new)

とした場合,次図のようなイメージで,5個の配列を作成して,それぞれの要素をAbcクラスのインスタンスで初期化していると勘違いしがちです.

ruby_array_1

実は,次図のように単に1つのインスタンスを参照しているだけなのです.

ruby_array_2

ではどう直したらよいでしょうか.正解はこれです.

class Abc
  attr_accessor :value
end

a = Array.new(5)

for i in 0..4
  a[i] = Abc.new
  a[i].value = i * 10
  p a[i]
end

puts "---"

for i in 0..4
  p a[i]
end

配列の要素ごとに,それぞれ個々のインタンスを生成及び参照しており,期待していた通りの結果となりました.

$ ruby test.rb
#<Abc:0x007fb8110d68c8 @value=0>
#<Abc:0x007fb8110d66e8 @value=10>
#<Abc:0x007fb8110d65d0 @value=20>
#<Abc:0x007fb8110d64b8 @value=30>
#<Abc:0x007fb8110d63c8 @value=40>
---
#<Abc:0x007fb8110d68c8 @value=0>
#<Abc:0x007fb8110d66e8 @value=10>
#<Abc:0x007fb8110d65d0 @value=20>
#<Abc:0x007fb8110d64b8 @value=30>
#<Abc:0x007fb8110d63c8 @value=40>

または,次のようにArrayオブジェクトを生成する際にmapメソッドで,それぞれインスタンスを生成して初期化してしまう方法もあります.これがスマートですかね.

class Abc
  attr_accessor :value
end

a = Array.new(5).map{Abc.new}

for i in 0..4
  a[i].value = i * 10
  p a[i]
end

puts "---"

for i in 0..4
  p a[i]
end

ご参考まで.

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中