配列オブジェクトに dupclone メソッドを実行すると、元のオブジェクトからコピーしたオブジェクトが新たに作られます。

dupclone は、オブジェクト自身を複製しますが、オブジェクトの指している先までは複製しません。つまり、C言語でいうポインターが指している先は同じものを指すことになります。全て異なるものではないので、浅いコピー(shallow copy)といいます。


a=[1,2,3]   # => [1, 2, 3]
b=[]        # => []
b << a      # => [[1, 2, 3]]
a << 4      # => [1, 2, 3, 4]
p b         # => [[1, 2, 3, 4]]

b を直接変更したわけではないが、 b に入れた a を操作しているので、 b に入れた a に影響を受け、 b 自体が変更されたように見えます。


p a           # => [1, 2, 3, 4]
c=[]          # => []
c << a.dup    # => [[1, 2, 3, 4]]
a << 5        # => [1, 2, 3, 4, 5]
p c           # => [[1, 2, 3, 4]]

dup により、 c に入れた要素自体をコピーしているので、 a を変更しても c には影響を及ぼしません。


つまり、 dupclone した配列やハッシュは異なっていても、中身のオブジェクトは同じものを参照しているということになります。


a = [{k: 'v1'}, {k: 'v2'}, {k: 'v3'}]
b = a.clone         # => [{:k=>"v1"}, {:k=>"v2"}, {:k=>"v3"}]
p a.object_id       # => 100740
p b.object_id       # => 98020
p a[0].object_id    # => 105120
p b[0].object_id    # => 105120

複製された b オブジェクトは a と異なるオブジェクト id を持っています。 中身はそのままコピーされるので、配列の中身の値は同じオブジェクトを参照しています。

2024/05/09