オブジェクトのコピーを作る
お金 | 仕事 | 勉強 | プライベート | 健康 | 心
プログラミング関連のコンテンツ
C言語/C++入門 | Ruby入門 | Python入門 | プログラミング全般
オブジェクトを作る場合、dup, clone メソッドを実行すると、元のオブジェクトからコピーしたオブジェクトが新規に作られます。
dup, clone は、オブジェクトのインスタンス変数をコピーする時に、浅いコピーを行い、値の参照をコピーして実際の値をコピーしません。
したがって、コピー先の変更が、コピー元まで影響する場合があります。
以下、実行例です。(Ruby1.9.1)
class IntAry attr_accessor :ints def initialize(*ints) @ints = ints end end obj3 = IntAry.new(5, 7, 8, 4, 3) p obj3.ints # => [5, 7, 8, 4, 3] 元の配列 obj3_cp = obj3.dup p obj3.object_id p obj3_cp.object_id obj3_cp.ints[1] = 32 # コピーしたオブジェクトの配列を変更 p obj3_cp.ints # => [5, 32, 8, 4, 3] p obj3.ints # => [5, 32, 8, 4, 3] コピー元オブジェクトの配列に影響
実行結果。
[5, 7, 8, 4, 3] 5892740 5892640 [5, 32, 8, 4, 3] [5, 32, 8, 4, 3]
object_id が違うのでコピーが行われていることが確認できます。
しかし、コピー先で行った「obj3_cp.ints[1] = 32」の変更が、コピー元のオブジェクト obj3 にまで及んでしまっています。
これは、意図した動作じゃないことのほうが多いはず。
initialize_copy メソッドを定義すれば、インスタンス変数である配列のコピーを作成できるようになります。
initialize_copy メソッドがなければ、コピーされたオブジェクトは、オリジナルのオブジェクトと同じ配列を参照することとなり、上記のような実行結果となったわけです。
class IntAry2 attr_accessor :ints def initialize(*ints) @ints = ints end def initialize_copy(orig) @ints = @ints.dup # 配列のコピーを作る end end obj4 = IntAry2.new(5, 7, 8, 4, 3) p obj4.ints # => [5, 7, 8, 4, 3] 元の配列 obj4_cp = obj4.dup p obj4.object_id p obj4_cp.object_id obj4_cp.ints[1] = 32 # コピーしたオブジェクトの配列を変更 p obj4_cp.ints # => [5, 32, 8, 4, 3] p obj4.ints # => [5, 7, 8, 4, 3] コピー元オブジェクトの配列に影響がない
実行結果。
[5, 7, 8, 4, 3] 5892230 5892130 [5, 32, 8, 4, 3] [5, 7, 8, 4, 3]
今度は、コピー元オブジェクトであるobj4は、コピー先オブジェクト変更の影響がありません。
cloneとdupは、オリジナルからオブジェクトをコピーする際に、インスタンス変数をコピーしたあとに、initialize_copy(orig) を呼び出す働きを持つ。
なお、cloneとdupの違いは、以下。
clone
dupオブジェクトの複製を作成して返します。
clone は freeze、taint、特異メソッドなどの情報も含めた完全な複製を、dup はオブジェクトの内容のみの複製を作ります。
clone や dup は「浅い(shallow)」コピーであることに注意してください。オブジェクト自身を複製するだけで、オブジェクトの指している先(たとえば配列の要素など)までは複製しません。
- - 関連記事 -
- 特異クラスによるクラスメソッド定義・class << self ~ end
- モジュールの使い方
- クラス定義でメソッドへのアクセス制限・public, private, protected
- クラス継承
- クラス拡張
- クラス変数・クラスメソッド
- アクセスメソッド(アクセサ)をattr_reader, attr_writer, attr_accessorで定義
- アクセスメソッド(アクセサ)
- Rubyのクラス定義・initialize(コンストラクタ)
- スーパークラスとサブクラス・クラス継承
- classメソッド・オブジェクトが属するクラスを調べる
- private, protected アクセス指定の違い
- Rubyのinitializeメソッドの継承