【发布时间】:2012-01-02 15:21:15
【问题描述】:
我做了一些搜索,发现了一些关于创建深拷贝操作符的不同方法和帖子。
在 Ruby 中是否有一种快速简单(内置)的方法来深度复制对象?这些字段不是数组或哈希。
在 Ruby 1.9.2 中工作。
【问题讨论】:
标签: ruby-on-rails ruby object copy deep-copy
我做了一些搜索,发现了一些关于创建深拷贝操作符的不同方法和帖子。
在 Ruby 中是否有一种快速简单(内置)的方法来深度复制对象?这些字段不是数组或哈希。
在 Ruby 1.9.2 中工作。
【问题讨论】:
标签: ruby-on-rails ruby object copy deep-copy
有一个本地实现来执行 ruby 对象的深度克隆:ruby_deep_clone
用 gem 安装它:
gem install ruby_deep_clone
示例用法:
require "deep_clone"
object = SomeComplexClass.new()
cloned_object = DeepClone.clone(object)
它比 Marshal 方法和事件处理冻结物体的速度快大约 6 到 7 倍。
【讨论】:
【讨论】:
你真的不需要宝石。这再简单不过了,这不值得一个 Gem 的开销!
def deep_clone(obj)
obj.clone.tap do |new_obj|
new_obj.each do |key, val|
new_obj[key] = deep_clone(val) if val.is_a?(Hash)
end
end
end
【讨论】:
自动深度克隆并不总是您想要的。通常您需要定义一些选定的属性来进行深度克隆。一种灵活的方法是实现initialize_copy、initialize_dup 和initialize_clone 方法。
如果你有课:
class Foo
attr_accessor :a, :b
end
而您只想深度克隆:b,则覆盖initialize_* 方法:
class Foo
attr_accessor :a, :b
def initialize_dup(source)
@b = @b.dup
super
end
end
当然,如果你想让@b 也深度克隆它自己的一些属性,你在 b 的类中也这样做。
Rails 会这样做(请参阅 https://github.com/rails/rails/blob/0951306ca5edbaec10edf3440d5ba11062a4f2e5/activemodel/lib/active_model/errors.rb#L78)
为了更完整的解释,我从这篇帖子https://aaronlasseigne.com/2014/07/20/know-ruby-clone-and-dup/学到了这里
【讨论】:
您可以为此使用重复的 gem。
它是一个小的纯红宝石,能够递归复制对象 它也会将它的对象引用复制到新的副本中。
require 'duplicate'
duplicate('target object')
【讨论】:
Rails 有一个名为deep_dup 的递归方法,它将返回对象的深层副本,并且与dup 和clone 相反,它甚至可以在复合对象(数组/哈希的数组/哈希)上工作。
很简单:
def deep_dup
map { |it| it.deep_dup }
end
【讨论】:
dup 调用。 Besdie Hash 和 Array,您需要实现自己的 deep_dup 才能使其工作。
我建议您使用 ActiveSupport gem,它为您的原生 Ruby 核心添加了很多糖,而不仅仅是 deep clone 方法。
您可以查看documentation 以获取有关已添加方法的更多信息。
【讨论】:
还可以查看 deep_dive。这允许您对对象图进行受控的深层副本。
【讨论】:
原始 Ruby 中没有内置深拷贝,但您可以通过编组和解组对象来破解它:
Marshal.load(Marshal.dump(@object))
但这并不完美,并且不适用于所有对象。更稳健的方法:
class Object
def deep_clone
return @deep_cloning_obj if @deep_cloning
@deep_cloning_obj = clone
@deep_cloning_obj.instance_variables.each do |var|
val = @deep_cloning_obj.instance_variable_get(var)
begin
@deep_cloning = true
val = val.deep_clone
rescue TypeError
next
ensure
@deep_cloning = false
end
@deep_cloning_obj.instance_variable_set(var, val)
end
deep_cloning_obj = @deep_cloning_obj
@deep_cloning_obj = nil
deep_cloning_obj
end
end
来源:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/43424
【讨论】:
Marshal.load(Marshal.dump(@object)) 效果很好。