7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

破壊的操作の観点から見たRubyの変数コピーの方法3種類

Posted at

あるオブジェクト(obj変数)をコピーしたいとき

大別すると3種類の方法がありそう。
ruby破壊的操作の特徴については以下にもまとめました。
http://qiita.com/metheglin/items/ca452bc0a3866d2de7bf

変数の代入の場合

参照の値渡しになるので、コピー先の変数から変更操作をおこなうとコピー元のデータも変わってしまう。
メソッドの引数に変数を渡す場合も代入になる。

## 代入による変数のコピー
obj = { name: 'Edgar Allan Poe', age: 10 }
obj_assign = obj

## 変更をおこなう
obj_assign[:name] = 'Peter Ilyich Tchaikovsky'

## コピー先のデータだけでなくコピー元のデータも変更されてしまう
obj
  # => {:name=>"Peter Ilyich Tchaikovsky", :age=>10}
obj_assign
  # => {:name=>"Peter Ilyich Tchaikovsky", :age=>10}

変数のcloneの場合

clone(またはdup)を使うと参照の値渡しではなく、コピーしたいオブジェクトを新規オブジェクトにコピーし、その参照が保持される。そのため、コピー元データとコピー先データを独立にすることができる。

obj = { name: 'Edgar Allan Poe', age: 10 }
obj_clone = obj.clone

## 変更をおこなう
obj_clone[:name] = 'Peter Ilyich Tchaikovsky'

## コピー先のデータのみが変更され、コピー元のデータは維持される
obj
  # => {:name=>"Edgar Allan Poe", :age=>10}
obj_clone
  # => {:name=>"Peter Ilyich Tchaikovsky", :age=>10}

ただし、objが参照している要素に対して破壊的メソッドを使うとcloneしても元のデータが変わってしまう。

obj = { name: 'Edgar Allan Poe', age: 10 }
obj_clone = obj.clone

## replace(破壊的変更・オブジェクト自体を変更)によって変更をおこなう
obj_clone[:name].replace 'Peter Ilyich Tchaikovsky'

## コピー先のデータだけでなくコピー元のデータも変更されてしまう
obj
  # => {:name=>"Peter Ilyich Tchaikovsky", :age=>10}
obj_clone
  # => {:name=>"Peter Ilyich Tchaikovsky", :age=>10}

こういうことが起きるのはたぶんcloneが以下の図のような原理で動くから。
スクリーンショット 2014-11-07 17.00.45.png

Marshalモジュールを使う場合

http://docs.ruby-lang.org/ja/2.1.0/class/Marshal.html
Marshalモジュールを使うと、オブジェクトがさらに参照するオブジェクトに対してもコピーしてくることができる。(深いコピー)
MarshalはjavascriptのJSONのようにオブジェクトの定義を文字列として出力したり、文字列からオブジェクトを復元したりするモジュールらしい。

obj = { name: 'Edgar Allan Poe', age: 10 }
obj_marshal = Marshal.load(Marshal.dump(obj))

## replace(破壊的変更・オブジェクト自体を変更)によって変更をおこなう
obj_marshal[:name].replace 'Peter Ilyich Tchaikovsky'

## コピー先のデータのみが変更され、コピー元のデータは維持される
obj
  # => {:name=>"Edgar Allan Poe", :age=>10}
obj_marshal
  # => {:name=>"Peter Ilyich Tchaikovsky", :age=>10}

スクリーンショット 2014-11-07 17.03.51.png

実行環境

% ruby -v                                                                                                                                                      (git)-[develop]
ruby 2.1.1p76 (2014-02-24 revision 45161) [x86_64-linux]
7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?