可能的原因红宝石不包含深克隆具有与问题的复杂性有关。请参阅最后的注释。
要生成一个将“深度复制”,“哈希”,“数组”和元素值的克隆,即,使每个元素的副本,在原来使得副本都会有相同的价值观,但新的对象,你可以这样做:如果你想重新定义Ruby的clone
方法的行为
class Object
def deepclone
case
when self.class==Hash
hash = {}
self.each { |k,v| hash[k] = v.deepclone }
hash
when self.class==Array
array = []
self.each { |v| array << v.deepclone }
array
else
if defined?(self.class.new)
self.class.new(self)
else
self
end
end
end
end
,你可以它只是clone
而不是deepclone
(在3个地方),但我不知道如何重新定义Ruby的克隆行为将影响Ruby库或Ruby on Rails,因此Caveat Emptor。就我个人而言,我不能推荐这样做。
例如:
a = {'a'=>'x','b'=>'y'} => {"a"=>"x", "b"=>"y"}
b = a.deepclone => {"a"=>"x", "b"=>"y"}
puts "#{a['a'].object_id}/#{b['a'].object_id}" => 15227640/15209520
如果你想你类deepclone得当,他们new
方法(初始化)必须能够deepclone那个类的一个对象的标准方式,即如果第一个参数被给出,它被假定为要被深度克隆的对象。
假设我们想要一个M类,例如。第一个参数必须是M类的可选对象。这里我们有第二个可选参数z
来预先设置新对象中z的值。
class M
attr_accessor :z
def initialize(m=nil, z=nil)
if m
# deepclone all the variables in m to the new object
@z = m.z.deepclone
else
# default all the variables in M
@z = z # default is nil if not specified
end
end
end
的z
预组克隆这里期间被忽略,但是你的方法可能有不同的行为。这个类的对象将这样创建:
# a new 'plain vanilla' object of M
m=M.new => #<M:0x0000000213fd88 @z=nil>
# a new object of M with m.z pre-set to 'g'
m=M.new(nil,'g') => #<M:0x00000002134ca8 @z="g">
# a deepclone of m in which the strings are the same value, but different objects
n=m.deepclone => #<M:0x00000002131d00 @z="g">
puts "#{m.z.object_id}/#{n.z.object_id}" => 17409660/17403500
当M级的对象是一个阵列的一部分:
a = {'a'=>M.new(nil,'g'),'b'=>'y'} => {"a"=>#<M:0x00000001f8bf78 @z="g">, "b"=>"y"}
b = a.deepclone => {"a"=>#<M:0x00000001766f28 @z="g">, "b"=>"y"}
puts "#{a['a'].object_id}/#{b['a'].object_id}" => 12303600/12269460
puts "#{a['b'].object_id}/#{b['b'].object_id}" => 16811400/17802280
注:
- 如果
deepclone
尝试克隆对象它不以标准方式克隆自己,它可能会失败。
- 如果
deepclone
试图克隆一个可以以标准方式克隆自身的对象,并且如果它是一个复杂的结构,它可能(也可能会)对其本身进行浅层克隆。
deepclone
不会深入复制哈希中的密钥。原因是他们通常不被视为数据,但如果您将hash[k]
更改为hash[k.deepclone]
,它们也将被深度复制。
- 某些元素值没有
new
方法,如Fixnum。这些对象总是具有相同的对象ID,并且被复制,而不被克隆。
- 要小心,因为当您进行深度复制时,在原始文件中包含相同对象的哈希或数组的两部分将在深克隆中包含不同的对象。
谢谢,埃文!好东西,我很欣赏基准。 :) – mway 2011-06-03 23:15:34
嘿@Evan Pon,我在你的例子中添加了[MessagePack](http://msgpack.org/)。这是一个不错的选择。 – 2012-07-06 04:37:53
MessagePack看起来非常快(比我的机器上的Custom快2倍)。你能否用建议更新答案而不是元帅? – 2013-02-03 09:31:03