Just do IT

思うは招く

Ruby の dup と clone の違い

Rubyのリファレンスにはこう書かれている。

dup はオブジェクトの内容, taint 情報をコピーし、 clone はそれに加えて freeze, 特異メソッドなどの情報も含めた完全な複製を作成します

  • dup はオブジェクト内容とtaint情報をコピーする
  • clone は上記に加えて、freezeや特異メソッドなどの情報も含めた完全なコピーをする

taintとは何か

taintメソッドは、selfを返すとのこと。Ruby 3.2 で削除される予定だそう。

何もせずに self を返します。このメソッドは Ruby 2.7 から deprecated で、Ruby 3.2 で削除予定です。

Object#taint (Ruby 3.1 リファレンスマニュアル)

> obj = 'hoge'
=> "hoge"

# taintメソッドを使ってみる
> obj.taint
=> "hoge"

上記のように、オブジェクトの値が返ってきた。

dupとcloneの違い

frozen?の結果はどうなるか?

dupの場合:freeze状態はコピーされない。

> origin = 'hoge'
=> "hoge"

# originをコピーする前にfreezeしておく
> origin.freeze
=> "hoge"

# dupする
> copy = origin.dup
=> "hoge"

# originは当然frozen
> origin.frozen?
=> true

# コピー先はfrozenではない!
> copy.frozen?
=> false

cloneの場合:freeze状態もコピーする。

> origin = 'hoge'
=> "hoge"

> origin.freeze
=> "hoge"

# dupではなくcloneしてコピーする
> copy = origin.clone
=> "hoge"

> origin.frozen?
=> true

# コピー先もfrozenになってる!
> copy.frozen?
=> true

特異メソッドはどうなるか?

dupの場合:特異メソッドはコピーされない。

> origin = 'hoge'
=> "hoge"

# 特異メソッドを定義する
> def origin.hello
>   puts 'hello'
> end
=> :hello

# 特異メソッドが生えた
> origin.hello
hello
=> nil

# dupする
> copy = origin.dup
=> "hoge"

# 特異メソッドはコピーされていないのでNoMethodErrorとなる
> copy.hello
'<main>': undefined method `hello' for "hoge":String (NoMethodError)

cloneの場合:特異メソッドもコピーする。

> copy = origin.clone
=> "hoge"

# 特異メソッドもコピーされている
> copy.hello
hello
=> nil

まとめ

  • dup はオブジェクト内容とtaint情報をコピーする
  • clone は上記に加えて、freezeや特異メソッドなどの情報も含めた完全なコピーをする

k-koh.hatenablog.com