最近勉強して出てきたshallow copy
について、まとめてみます。
新米エンジニアなので、誤りがあったらご指摘ください
shallow copyとは
かなりざっくり「外見は別物だけど、中身は一緒だよ」というコピー
-
aオブジェクトと、それをコピーしてできたbオブジェクトがあった場合...
- aオブジェクトとbオブジェクトは、別々の
object_id
だよ(外見は別物)
- aオブジェクトとbオブジェクトが指してるオブジェクト(配列の要素など)の参照先は一緒だよ(中身は一緒)
- aオブジェクトとbオブジェクトは、別々の
というコピーのこと。
Rubyだと、clone
やdup
でshallow copy
ができます。
文字だけだと何を言っているか分かりにくいので、次にいきましょう。
見てみよう
※分かりやすくするために、object_id
をメモリの番地としています。(object_id
は適当です)
1. shallow copy
元と、copy
先のobject_id
は別々ある(外見は別物)
a = ["a", "b", "c"]
b = a.clone
# 外見は別物
p a.object_id # 60
p b.object_id # 80
2. shallow copy
元と、copy
先が指してるオブジェクトの参照先は一緒(中身は一緒)
a = ["a", "b", "c"]
b = a.clone
# 外見は別物
p a.object_id # 60
p b.object_id # 80
# 中身の参照先は一緒
p a[0].object_id # 10
p b[0].object_id # 10
p a[1].object_id # 20
p b[1].object_id # 20
p a[2].object_id # 30
p b[2].object_id # 30
外見が違うと
外見が違う(object_id
が異なる)ので、aオブジェクトに対する変更(外見に対する変更)は、bオブジェクトに影響を及ぼしません。
- aオブジェクトに要素
"d"
を追加する
a = ["a", "b", "c"]
b = a.clone
a.push("d")
p a # ["a", "b", "c", "d"]
p b # ["a", "b", "c"]
p a[3].object_id # 40
- aオブジェクトの
[0]
要素の参照先を変更する
a = ["a", "b", "c"]
b = ary.clone
a[0] = "d" # 破壊的な変更ではなく、参照先の変更なので、新しいオブジェクトが作られる
p a # ["d", "b", "c"]
p b # ["a", "b", "c"]
p a[0].object_id # 40
中身が一緒なので
こんなことが起こります。
参照先に破壊的な変更を加えると、両方とも変わる
a = ["a", "b", "c"]
b = ary.clone
# 参照先に破壊的変更を加える
a[0].upcase!
p a # ["A", "b", "c"]
p b # ["A", "b", "c"]
そもそも=
とclone
の違い
ここで、=
の挙動も見て、clone
との違いを確認しましょう。
a = ['a','b','c']
b = a # aが参照しているのと同じメモリ番地にある['a', 'b', 'c']を、bも参照するようになる
p a.object_id # 60
p b.object_id # 60
参考
shallow copyについて
メモリ?番地?参照?という方へ