【Ruby】ハッシュや配列の使い回し・再利用で値が上書きされる

Ruby/Rails
スポンサーリンク

はじめに

Rubyは値を代入するのではなく、実際に値が保存されているメモリの場所を代入しています。(参照渡し)

PHPとかだと普通は値渡しで代入されるので、Rubyを使っていて混乱したのでまとめます。

ハッシュを使い回して変数に代入してみる

検証コード

reports = {}

#----------------------
reports["subject"] = "Math"
reports["score"] = 60

str_math = reports

reports["subject"] = "English"
reports["score"] = 20

str_english = reports

#----------------------
puts str_math    #{"subject"=>"Math", "score"=>60}となるはず
puts str_english #{"subject"=>"English", "score"=>20}となるはず

いつもの感覚だと、
str_math は {“subject”=>”Math”, “score”=>60}
str_english {“subject”=>”English”, “score”=>20}となるはずですが…はたして…?

実行結果

{"subject"=>"English", "score"=>20}
{"subject"=>"English", "score"=>20}

str_math と str_english どちらも{“subject”=>”English”, “score”=>20} となってしまっています。

なぜハッシュや配列の使い回し・再利用で値が上書きされるのか

上記の検証コードに、対象のオブジェクト(ハッシュ・変数)に割り当てられているメモリの場所的なものを表示する処理を追加して、動きを確認してみます。(正確には、Rubyがオブジェクトに割り当てている整数値を返します。)

object_idを表示するよう変更して再検証

reports = {}
puts reports.object_id

puts "----------------------"
reports["subject"] = "Math"
reports["score"] = 60

str_math = reports
puts str_math
puts str_math.object_id

reports["subject"] = "English"
reports["score"] = 20

str_english = reports
puts str_english
puts str_english.object_id

puts "----------------------"
puts str_math          ###{"subject"=>"Math", "score"=>60}となるはず
puts str_english       ###{"subject"=>"English", "score"=>20}となるはず

再検証の実行結果

7815320
----------------------
{"subject"=>"Math", "score"=>60}
7815320
{"subject"=>"English", "score"=>20}
7815320
----------------------
{"subject"=>"English", "score"=>20}
{"subject"=>"English", "score"=>20}

解説

reports.object_id や str_math.object_id のようにobject_idを出力しています。

reports、str_math、str_englishそれぞれでobject_idを出力していますが、どれも「7815320」で共通していますね。つまり、三つともすべて同じ場所を参照していることを意味します。

拙い図ですが…
図1のように値が変数に代入されるのではなく、

図1 値が代入されると思っている時のイメージ

図2のように値が入っているメモリの場所を代入しているというわけです。

図2 実際は値が入っているメモリの場所が代入されている

コメント

タイトルとURLをコピーしました