2016-08-30 5 views
1

私は実際に浅いコピーと深いコピーの違いを理解していません。私がテストするとRubyの#dupは深いコピーを作成するようです。 ルビーでディープコピーが必要な最も単純な例を提供

Produces a shallow copy of obj---the instance variables of obj are 
copied, but not the objects they reference. 
しかし、私はこれをテストするとき、彼らが参照するオブジェクトを変更するようだ:

ドキュメントは述べています。

class Klass 
    attr_accessor :name 
end 

a = Klass.new 
a.name = "John" 
b = a.dup 
b.name = "Sue" 
puts a.name # John 

@nameobjects they referenceの一つであるのに、なぜ十分な浅いコピーはここですか?
最も簡単なものディープコピーが必要な例ですか?

答えて

1

表示されている例では、深いコピーと浅いコピーの違いについては説明していません。

class Klass 
    attr_accessor :name 
end 

anna = Klass.new 
anna.name = 'Anna' 

anna_lisa = anna.dup 
anna_lisa.name << ' Lisa' 
# => "Anna Lisa" 

anna.name 
# => "Anna Lisa" 

一般的に、dupcloneが両方ちょうどあなたが上のメソッドを呼び出している実際のオブジェクトを複製することが期待されています。その代わり、この例を考えてみましょう。上の例のname文字列のような他の参照オブジェクトは複製されません。したがって、複製後、元と複製オブジェクトの両方が非常に同じ名前文字列を指します。

deep_dupでは、一般的にすべての(関連する)参照オブジェクトも複製されます。多くの場合、無限深度に複製されます。これは可能なすべてのオブジェクト参照に対して達成するのが難しいため、ハッシュや配列などの特定のオブジェクトの実装に依存することがよくあります。

かなり一般的なディープ・ダップの一般的な回避策は、RubyのMarshalクラスを使用してオブジェクト・グラフを直列化し、再度それを直接直列化解除することです。

anna_lena = Marshal.load(Marshal.dump(anna)) 

これは新しいオブジェクトを作成し、事実上deep_dupです。ほとんどのオブジェクトはすぐにマーシャリングをサポートするため、これはかなり強力なメカニズムです。ただし、リモートコード実行の脆弱性が生じるため、ユーザーが提供したデータをアンマーシャリング(つまりload)しないでください。

+0

あなたは正しいです、私は文字列を変更していない、私の例でそれを再割り当て。 –

1

これを試してみてください:

DUPを使用する場合は、オブジェクトは で拡張されているすべてのモジュールがコピーされません:。

class Klass 
    attr_accessor :name 
end 

a = Klass.new 
a.name = Klass.new #object inside object 
a.name.name = 'George' 
b = a.dup 
puts b.name.name # George 

b.name.name = 'Alex' 
puts a.name.name # Alex 

はまた(see info)ことに注意してください

編集: 文字列は元のシナリオではコピーされない参照されている(これは見つけるために面白かった)文字列に注意してください。これはこのケースで証明されています。

a.name = 'George' 
puts a.name.object_id # 69918291262760  

b = a.dup 
puts b.name # George 
puts b.name.object_id # 69918291262760 

b.name.concat ' likes tomatoes' # append to existing string 
puts b.name.object_id # 69918291262760 

puts a.name # George likes tomatoes 

これは期待どおりに動作します。参照されたオブジェクト(文字列を含む)はコピーされず、参照を共有します。

なぜ元の例もあまり表示されませんか? b.nameを別のものに設定すると、新しい文字列に設定されるからです。

a.name = 'hello' 

このため、本当に短い手ではありません:

a.name = String.new('hello') 

は、したがって、元の例では、a.name & b.nameは、同じオブジェクトを参照しなくなっている、あなたは見ることのobject_idを確認することができます。

Fixnum、浮動小数点数、真、偽、または記号には当てはまりません。これらのオブジェクトは、浅いコピーに複製されます。

+0

優秀なsuccintの例ですが、これによって '#dup'が失敗するのはなぜですか?これは私を混乱させている。 –

+0

これは、文字列オブジェクトの特別な場合を説明するのに役立ちます。 fixnumやシンボルは、実際のオブジェクトではなく、単にそれらのように動作します。Stringは、スペースを節約するための特別なメソッドを持っています。彼らはfixnumsのような '普通の'オブジェクトでも偽のオブジェクトでもありません:http://patshaughnessy.net/2012/1/18/seeing-double-how-ruby-shares-string-values – ABrowne

+0

ありがとう。私は行く必要があり、私は明日これを読むでしょう。 –

関連する問題