参照の値渡しについて

# はじめに

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

> Rubyist Magazine
> [値渡しと参照渡しの違いを理解する](https://magazine.rubyist.net/articles/0032/0032-CallByValueAndCallByReference.html)

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

# 不思議の共有

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

```rb
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]
```

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

```rb
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 リファレンスマニュアル\)](https://docs.ruby-lang.org/ja/latest/method/Object/i/object_id.html)

```rb
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`という値を代入しているようです。

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

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

これは`100`などのInteger型のオブジェクトなどと異なります。
Integer型だけでなく、TrueClass, FalseClass, NilClass, Symbolなども同様です。
[Object\#object\_id \(Ruby 3\.0\.0 リファレンスマニュアル\)](https://docs.ruby-lang.org/ja/latest/method/Object/i/object_id.html)

```rb
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
```

# `capitalize`と`capitalize!`を活用してみる

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

```rb
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`を使ってみる

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

```rb
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_id`が`70233185061420`であるオブジェクトを参照しています。
しかし、`name2`は、`object_id`が`70233185108640`であるオブジェクトを参照しています。

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

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

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

```rb
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_id`が`70164238885440`であるオブジェクト自身に変更を加えたのです。

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

# 不思議を解き明かす

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

```rb
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]
```

```rb
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
```

# 参考

- [値渡しと参照渡しの違いを理解する](https://magazine.rubyist.net/articles/0032/0032-CallByValueAndCallByReference.html)
- [Rubyの破壊的メソッドと参照の値渡し \- Qiita](https://qiita.com/metheglin/items/ca452bc0a3866d2de7bf)
- [【Ruby】メソッドの引数は値渡し？参照渡し？ \- Qiita](https://qiita.com/hogucc/items/39c89c25a39d15b41f4e)