提供在 ruby 中需要深度复制的最简单示例

Provide simplest example where deep copy is needed in ruby

真搞不懂浅拷贝和深拷贝的区别。 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 之一时,为什么这里的浅拷贝就足够了?
需要深度复制的最简单示例是什么?

试试这个:

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):

When using dup, any modules that the object has been extended with will not be copied.

编辑:关于字符串的注释(这很有趣) 字符串在原始场景中被引用而不是被复制。通过这个案例证明了这一点:

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、浮点数、true、false 或符号不是这种情况。这些对象在浅拷贝中被复制。

你给出的例子没有说明深拷贝和浅拷贝的区别。相反,考虑这个例子:

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,通常所有(相关)引用对象也会被复制,通常复制到无限深度。由于对于所有可能的对象引用都很难实现,因此人们通常依赖于特定对象(如哈希和数组)的实现。

一个相当通用的 deep-dup 的常见解决方法是使用 Ruby 的 Marshal class 序列化对象图并直接再次反序列化它。

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

这会创建新对象,实际上是 deep_dup。由于大多数对象立即支持封送处理,因此这是一个相当强大的机制。请注意,您永远不应解组(即 load)用户提供的数据,因为这会导致远程代码执行漏洞。