祝 初投稿🎉
自分が理解する上で一番悩んだ参照の値渡しを
できるだけ噛み砕いてイメージで説明してみた。
ずれてる!
違う!
等あれば感想でご指摘いただくようお願いします。
この話はshallow copyやdeep copyの話に繋がるため、
rubyを操る上では大事。
参照の値渡しとは?
簡単に言ってしまえば、
引数で使うメモリ位置(<0x00000001>とか)らしきものを値で渡しちまおうぜ!
っていうような考え方。
とりあえずはメモリ位置の認識でいいかも。
〜渡し
っていうのは引数同士のコピーで起こる動作をそれっぽく言ったものとして掴んでおけばOK
そんなメモリ位置に入らねぇよってツッコミはなし。
文字列型と数値型の値の参照渡し
first = 1
second = first
p first
p second
のときの動作としてはこんな感じ
これをそのまま出力するとこうなる。
1
1
これを代入し直すと
second = 2
p first
p second
こんな動きになる。
出力はもちろん
1
2
ここまでは値渡しと同じ見た目のため、混同されやすい。
とりあえずは、
参照しているメモリの値がメモリ番号から他のオブジェクト(今回は数値型)に切り替わることで、値渡しと同じような動作になる
文字列も原理は同じため省略。
リストとハッシュの参照の値渡し
rubyの配列の話。
個人的にはリスト
の方がしっくりくるので以後配列
はリスト
と呼称する。
first_list = [1,2]
second_list= first_list
p first_list
p second_list
このときの出力はもちろんこうなる。
[1,2]
[1,2]
さぁ代入してみよう
second_list[0]=3
p first_list
p second_list
このとき、参照の値渡しを知らないとこのような出力を期待する。
[1,2]
[3,2]
無慈悲にも実際にはこう
[3,2]
[3,2]
え、なんで?
このときの内部の動きを見てみる。
ここから少しややこしいので注意。
最初のコピーの時
代入時
こうなる。
rubyの特性上リストもオブジェクトのため、
その配下の別のオブジェクト(今回は数値型のオブジェクト)の値が入れ替わる。
つまり、
リスト・ハッシュの代入の際は、リスト・ハッシュに代入するのではなく、配下のオブジェクトに代入している
この事象を回避したい!
回避するためには、実際に見られる値自体を複製する必要がある。
一番手軽な方法はこちら
first_list=[1,2]
second_list=first_list.map{ |num| num }
p first_list
p second_list
second_list[0] = 3
p first_list
p second_list
出力はこう
[1,2]
[1,2]
[1,2]
[3,2]
なぜ?
中でこのように新しいリストを作成しつつ、
mapメソッドを使用してリスト配下のオブジェクト自体ををコピーしている。(最初の数値型と同じコピー)
その後に行う代入も最初のコピーと同じ動作が起こる。
まとめ
- rubyではコピーされる際に、対象のオブジェクトの位置をコピーする。
- 参照の値渡しは、メモリ番号らしきものをコピーする。
- 参照の値渡しも図にしちゃえば怖くない。
rubyの学習を進めていくと object_idやら何やら出てきますが、メモリ位置のようなものとして受け取っておけば理解しやすいです。
ざっくり説明するために細かい言葉などは正確ではありませんが、この記事が誰かの役に立てば嬉しいです。