2012-04-17 2 views
186

Ruby docs for dupは言う:一般的にRubyのdupとcloneの違いは何ですか?

clonedupは下位クラスで異なる意味を有することができます。 cloneは、内部状態を含むオブジェクトの複製に使用されますが、dupは通常、新しいインスタンスを作成するために子孫オブジェクトのクラスを使用します。私は私が見つけたいくつかのテストを行う際に

は、しかし、彼らは実際には同じです:

class Test 
    attr_accessor :x 
end 

x = Test.new 
x.x = 7 
y = x.dup 
z = x.clone 
y.x => 7 
z.x => 7 

だから2つの方法の間の違いは何ですか?

+26

私は*何* 'dup'と' clone'はありませんが、*なぜあなたはいずれかを使用したい*で、単なる違いありません知っていたいです他のものよりむしろ。 –

+1

こちらも良いリンクです - https://coderwall.com/p/1zflyg –

答えて

262

サブクラスは、異なるセマンティクスを提供するためにこれらのメソッドをオーバーライドできます。 Objectには、2つの重要な違いがあります。まず

cloneコピーシングルトンクラス、dupはそうではありません。 dupはそうではない

o = Object.new 
def o.foo 
    42 
end 

o.dup.foo # raises NoMethodError 
o.clone.foo # returns 42 

第二に、cloneは、凍結状態を維​​持します。

class Foo 
    attr_accessor :bar 
end 
o = Foo.new 
o.freeze 

o.dup.bar = 10 # succeeds 
o.clone.bar = 10 # raises RuntimeError 

Rubinius implementation for these methods それは非常に明確で、かつかなり準拠したRubyの実装であるため、多くの場合、これらの質問に対する答えのための私のソースです。

+13

これをもう一度変更しようとする場合:Rubyでよく定義された用語である「シングルトンクラス」には、シングルトン*メソッドだけでなく、シングルトンクラスで定義された定数も含まれます。次のことを考慮してください。 'o = Object.new;クラス<< o; A = 5;終わり; puts(クラス<< o.clone; A; end); puts(クラス<< o.dup; A; end) '。 –

+1

すばらしい答え、それに続いてすばらしいコメントがありましたが、それはその文法を理解するために野生のガチョウの追跡に私を導いた。これは混乱するかもしれない他の誰かを助けるでしょう:http://www.devalot.com/articles/2008/09/ruby-singleton – davidpm4

+1

"シングルトンクラス"には、元のオブジェクトに対して 'extend'されました。だから 'Object.new.extend(Enumerable).dup.is_a?(Enumerable)'はfalseを返します。 – Daniel

28

凍ったオブジェクトとの違いが1つあります。フリーズされたオブジェクトのcloneもフリーズされます(フリーズされたオブジェクトのdupはそうではありません)。

class Test 
    attr_accessor :x 
end 
x = Test.new 
x.x = 7 
x.freeze 
y = x.dup 
z = x.clone 
y.x = 5 => 5 
z.x = 5 => TypeError: can't modify frozen object 

別の違いはシングルトン方式です。ここでも同じ話、dupはコピーされませんが、cloneはコピーします。

def x.cool_method 
    puts "Goodbye Space!" 
end 
y = x.dup 
z = x.clone 
y.cool_method => NoMethodError: undefined method `cool_method' 
z.cool_method => Goodbye Space! 
+0

これは私にとって非常に便利でした。固定定数を作成し、これを次のように渡す場合は、https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L248(RailsのCookie処理)を実行します。彼らがあなたに知らせなくても簡単にエラーを出してクローンを修正しようとします。あなたの凍った価値を騙し、それを渡すことで、ここでラックを壊すことなく、間違いなくあなたの定数を間違って修正することはないと少なくとも保証することができます。 – XP84

151

のActiveRecordを扱って有意な差があまりにもあります:あなたは.save

category2 = category.dup 
#=> #<Category id: nil, name: "Favorites"> 

cloneを押すことで、データベースに新しいオブジェクトを保存することができますので、

dupは、そのIDが設定されずに新しいオブジェクトを作成します同じIDを持つ新しいオブジェクトを作成するので、その新しいオブジェクトに加えられたすべての変更は、当てはまるとオリジナルのレコードを上書きします。.save

category2 = category.clone 
#=> #<Category id: 1, name: "Favorites"> 
+35

この回答は、IMOが最も重要な実用的な情報を持っているものです。他の回答はエソテリカに属していますが、この回答は重要な実用的な違いを示しています。 – jpwynn

+26

上記はActiveRecordに特有のものです。この区別は、標準のRubyでははるかに微妙です。 – ahmacleod

+1

@Stefanと@jvalanen: 'ActiveRecord'オブジェクトに' dup'メソッドと 'clone'メソッドを適用しているとき、私はあなたが答えで述べたことの逆の結果を得ています。これは 'dup'を使用しているときに' id'が設定された新しいオブジェクトを作成し、 'clone'を使って' id'が設定されていないオブジェクトを作成することを意味します。それをもう一度見てクリアしてもらえますか? 。 Thnx –

2

どちらもほぼ同じですが、クローンはdupよりももう1つのことを行います。クローンでは、オブジェクトのフリーズされた状態もコピーされます。 dupでは、常に解凍されます。

f = 'Frozen'.freeze 
    => "Frozen" 
f.frozen? 
    => true 
f.clone.frozen? 
    => true 
f.dup.frozen? 
    => false 
3

newer docが良い例が含まれています

class Klass 
    attr_accessor :str 
end 

module Foo 
    def foo; 'foo'; end 
end 

s1 = Klass.new #=> #<Klass:0x401b3a38> 
s1.extend(Foo) #=> #<Klass:0x401b3a38> 
s1.foo #=> "foo" 

s2 = s1.clone #=> #<Klass:0x401b3a38> 
s2.foo #=> "foo" 

s3 = s1.dup #=> #<Klass:0x401b3a38> 
s3.foo #=> NoMethodError: undefined method `foo' for #<Klass:0x401b3a38> 
関連する問題