1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

参照の値渡しについて

Last updated at Posted at 2021-12-19

はじめに

Rubyist Magazineでは、「参照の値渡し」が解説されています。

Rubyist Magazine
値渡しと参照渡しの違いを理解する

ただ、具体的かつ簡単なコードを題材にして理解したかったので、ざっくりと調べてみました。
(初学者が書くことなので間違い等があると思いますが、参考までにご覧ください)

不思議の共有

まず、「参照の値渡し」の前に、事情をよく分かっていない方にとっては不思議な事象を紹介します。
「参照の値渡し」を学びつつ、この不思議を解き明かしていきます。

irb(main):001:0> array = [1, 2, 3]
=> [1, 2, 3]
irb(main):002:0> array2 = array
=> [1, 2, 3]
irb(main):003:0> array[0] = 100
=> 100
irb(main):004:0> array
=> [100, 2, 3]
# なんと、array2も変更されているではないか!
irb(main):005:0> array2
=> [100, 2, 3]

けど、このケースだと、もう一方の変数に変更がないんです。
私だけですかね、不思議じゃないですか?

irb(main):001:0> num = 100
=> 100
irb(main):002:0> num2 = num
=> 100
irb(main):003:0> num = 5
=> 5
irb(main):004:0> num
=> 5
# あれ、num2は100のままだ・・・
irb(main):005:0> num2
=> 100

object_idを活用してみる

では、事例を大幅に変更して、この問題を紐解いていきます。
代入するものをString型に変更します。そして、object_idというメソッドを使っていきます。

object_idというメソッドを使うと、オブジェクト固有のidを取得できます。
object_idメソッドを活用し、以下のケースにおいて、どのオブジェクトが参照されているか確かめます。
Object#object_id (Ruby 3.0.0 リファレンスマニュアル)

irb(main):001:0> name = 'dyson'
=> "dyson"
irb(main):002:0> name2 = name
=> "dyson"
irb(main):003:0> name.object_id
=> 70145544766620
irb(main):004:0> name2.object_id
=> 70145544766620
irb(main):005:0> name
=> "dyson"
irb(main):006:0> name2
=> "dyson"

上記のケースにおいては、'dyson'という値を渡しているのではないようです。
正確には、'dyson'object_idという値を代入しているようです。

参照するオブジェクトが同一なので、namename2の返り値は、'dyson'になります。

なお、String型は「打ち込む」度に新しいオブジェクトとして生成されます。
新しいオブジェクトなので、object_idは毎回変わります。

これは100などのInteger型のオブジェクトなどと異なります。
Integer型だけでなく、TrueClass, FalseClass, NilClass, Symbolなども同様です。
Object#object_id (Ruby 3.0.0 リファレンスマニュアル)

irb(main):001:0> 'dyson'.object_id
=> 70133892810380
irb(main):002:0> 'dyson'.object_id
=> 70133892796800
irb(main):003:0> 'dyson'.object_id
=> 70133892766900
irb(main):004:0> 100.object_id
=> 201
irb(main):005:0> 100.object_id
=> 201
irb(main):006:0> 100.object_id
=> 201

capitalizecapitalize!を活用してみる

capitalizeは非破壊的メソッドですが、capitalize!は破壊的メソッドです。
破壊的メソッドを使うと、そのオブジェクト自身に変更を加えることができます。

irb(main):001:0> name = 'dyson'
=> "dyson"
irb(main):002:0> name.capitalize
=> "Dyson"
irb(main):003:0> name
=> "dyson"
irb(main):004:0> name.capitalize!
=> "Dyson"
irb(main):005:0> name
=> "Dyson"

非破壊的メソッドcapitalizeを使ってみる

この違いを活用して、実験してみます。

irb(main):001:0> name = 'dyson'
=> "dyson"
irb(main):002:0> name2 = name
=> "dyson"
irb(main):003:0> name.object_id
=> 70233185108640
irb(main):004:0> name2.object_id
=> 70233185108640
irb(main):005:0> name
=> "dyson"
irb(main):006:0> name2
=> "dyson"
irb(main):007:0> name = name.capitalize
=> "Dyson"
irb(main):008:0> name.object_id
=> 70233185061420
irb(main):009:0> name2.object_id
=> 70233185108640
irb(main):010:0> name
=> "dyson"
irb(main):011:0> name2
=> "Dyson"

最終的に、nameは、object_id70233185061420であるオブジェクトを参照しています。
しかし、name2は、object_id70233185108640であるオブジェクトを参照しています。

nameに代入しているのは、namecapitalizeしてできた、新しいオブジェクトです。
namename2が参照するobject_idは異なるため、namename2の返り値も異なります。

破壊的メソッドcapitalize!を使ってみる

続いて、capitalize!メソッドを使って実験してみます。
capitalize!を使うと、オブジェクト自身に変更を加えることができます。

irb(main):001:0> name = 'dyson'
=> "dyson"
irb(main):002:0> name2 = name
=> "dyson"
irb(main):003:0> name.object_id
=> 70164238885440
irb(main):004:0> name2.object_id
=> 70164238885440
irb(main):005:0> name = name.capitalize!
=> "Dyson"
irb(main):006:0> name.object_id
=> 70164238885440
irb(main):007:0> name2.object_id
=> 70164238885440
irb(main):008:0> name
=> "Dyson"
irb(main):009:0> name2
=> "Dyson"

ここでは、‘dyson’というオブジェクト自体に変更を加えました。

name = name.capitalize!の実施前後でobject_idに変化がないことからも分かりますが、
'Dyson'という新しく生成したオブジェクトを代入したのではありません。
object_id70164238885440であるオブジェクト自身に変更を加えたのです。

nameも、name2も、参照しているのは同一のオブジェクトです。
‘Dyson’というオブジェクトになったので、name及びname2の返り値が‘Dyson’になりました。

不思議を解き明かす

では、あえて解説もしませんが、これで不思議が分かったのではないでしょうか?

irb(main):001:0> array = [1, 2, 3]
=> [1, 2, 3]
irb(main):002:0> array2 = array
=> [1, 2, 3]
irb(main):003:0> array.object_id
=> 70168202066140
irb(main):004:0> array2.object_id
=> 70168202066140
irb(main):005:0> array[0] = 100
=> 100
irb(main):006:0> array
=> [100, 2, 3]
irb(main):007:0> array.object_id
=> 70168202066140
irb(main):008:0> array2.object_id
=> 70168202066140
irb(main):009:0> array2
=> [100, 2, 3]
irb(main):001:0> num = 100
=> 100
irb(main):002:0> num2 = num
=> 100
irb(main):003:0> num.object_id
=> 201
irb(main):004:0> num2.object_id
=> 201
irb(main):005:0> num = 5
=> 5
irb(main):006:0> num.object_id
=> 11
irb(main):007:0> num2.object_id
=> 201
irb(main):008:0> num2
=> 100

参考

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?