为什么Ruby中没有深层复制方法?
我正在研究技术图纸(svg / ruby)的解决方案。 我想操纵矩形,并add!
这个类中的方法:
class Rect def add!(delta) @x1+=delta ... # and so on self end end
我还需要一个返回Rect
的add
方法,但不需要操作self
:
def add(delta) r=self.dup/clone/"copy" # <-- not realy the 3 and no quotes, just in text here r.add! delta end
dup
和clone
不做我的事情,但是:
def copy; Marshal.load(Marshal.dump(self)); end
确实。
为什么普通Ruby中不存在这样的基本function? 请不要告诉我,我可以反向add
和add!
,让add
完成工作,并add!
叫它。
我不确定为什么在Ruby中没有深度复制方法,但我会尝试根据我能找到的信息进行有根据的猜测(参见该行下面的链接和引号)。
从这些信息来看,我只能推断Ruby没有深度复制方法的原因是因为它很少需要,并且在少数情况下确实需要,还有其他相对简单的方法来完成相同的任务:
如您所知,目前使用Marshal.dump
和Marshal.load
是推荐的方法。 这也是Programming Ruby推荐的方法(参见下面的摘录)。
或者,在这些gem中至少有3个可用的实现: deep_cloneable
, deep_clone
和ruby_deep_clone
; 第一个是最受欢迎的。
相关信息
这是对comp.lang.ruby的讨论 ,可能会对此有所了解。 这里有另一个答案与一些相关的讨论,但这一切都回到使用Marshal
。
在编程Ruby中没有提到深度复制,但在Ruby编程语言中有一些提及。 以下是一些相关的摘录:
[…]
Marshal.dump
和Marshal.load
另一个用途是创建对象的深层副本:def deepcopy(o) Marshal.load(Marshal.dump(o)) end
[…]
…
Marshal.dump
和Marshal.load
使用的二进制格式依赖于版本,并且不保证较新版本的Ruby能够读取旧版本Ruby编写的编组对象。[…]
请注意,文件和I / O流以及Method和Binding对象太动态,无法编组; 没有可靠的方法来恢复他们的状态。
[…]
不要对数组进行防御性深层复制,只需在其上调用
to_enum
,然后传递生成的枚举数而不是数组本身。 实际上,您正在为数组创建一个可枚举但不可变的代理对象。
忘记编组。 deep_dive gem将解决您的问题。
为什么你不能使用这样的东西:
new_item = Item.new(old_item.attributes) new_item.save!
这会将所有属性从现有项复制到新项,而不会出现问题。 如果您有其他对象,则可以单独复制它们。
我认为这是复制对象的最快方法