提供在 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
当 @name
是 objects 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"
通常,dup
和 clone
都应该只是复制您调用方法的实际对象。上例中的 name
字符串等其他引用对象不会重复。因此,在复制之后,原始对象和复制对象都指向同一个名称字符串。
对于 deep_dup
,通常所有(相关)引用对象也会被复制,通常复制到无限深度。由于对于所有可能的对象引用都很难实现,因此人们通常依赖于特定对象(如哈希和数组)的实现。
一个相当通用的 deep-dup 的常见解决方法是使用 Ruby 的 Marshal class 序列化对象图并直接再次反序列化它。
anna_lena = Marshal.load( Marshal.dump(anna))
这会创建新对象,实际上是 deep_dup。由于大多数对象立即支持封送处理,因此这是一个相当强大的机制。请注意,您永远不应解组(即 load
)用户提供的数据,因为这会导致远程代码执行漏洞。
真搞不懂浅拷贝和深拷贝的区别。 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
当 @name
是 objects 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"
通常,dup
和 clone
都应该只是复制您调用方法的实际对象。上例中的 name
字符串等其他引用对象不会重复。因此,在复制之后,原始对象和复制对象都指向同一个名称字符串。
对于 deep_dup
,通常所有(相关)引用对象也会被复制,通常复制到无限深度。由于对于所有可能的对象引用都很难实现,因此人们通常依赖于特定对象(如哈希和数组)的实现。
一个相当通用的 deep-dup 的常见解决方法是使用 Ruby 的 Marshal class 序列化对象图并直接再次反序列化它。
anna_lena = Marshal.load( Marshal.dump(anna))
这会创建新对象,实际上是 deep_dup。由于大多数对象立即支持封送处理,因此这是一个相当强大的机制。请注意,您永远不应解组(即 load
)用户提供的数据,因为这会导致远程代码执行漏洞。