为什么Ruby中没有深层复制方法?

时间:2013-07-28 20:19:58

标签: ruby copy deep-copy

我正在研究技术图纸(svg / ruby​​)的解决方案。我想操纵矩形,并在这个类中有一个add!方法:

class Rect
  def add!(delta)
    @x1+=delta 
    ... # and so on
    self
  end
end

我还需要add方法返回Rect,但不能操纵self

def add(delta)
  r=self.dup/clone/"copy" # <-- not realy the 3 and no quotes, just in text here
  r.add! delta
end

dupclone不做我的事情,但是:

def copy; Marshal.load(Marshal.dump(self)); end

确实

为什么普通Ruby中不存在这样的基本功能?请不要告诉我,我可以撤消addadd!,让add完成工作,然后add!调用它。

3 个答案:

答案 0 :(得分:5)

我不确定为什么Ruby中没有深层复制方法,但我会尝试根据我能找到的信息进行有根据的猜测(参见该行下面的链接和引号)。

从这些信息来看,我只能推断Ruby没有深度复制方法的原因是因为它很少需要,并且在极少数情况下它确实是必要的,还有其他相对简单的方法来实现同样的任务:

如您所知,目前推荐使用Marshal.dumpMarshal.load来执行此操作。这也是Programming Ruby推荐的方法(参见下面的摘录)。

或者,在这些宝石中至少有3个可用的实现:deep_cloneabledeep_cloneruby_deep_clone;第一个是最受欢迎的。


相关信息

这里的a discussion over at comp.lang.ruby可能会对此有所了解。 another answer here有一些相关的讨论,但这一切都回到使用Marshal

Programming Ruby中没有提及任何深度复制,但在The Ruby Programming Language中有一些提及。以下是一些相关的摘录:

  

[...]

     

Marshal.dumpMarshal.load的另一个用途是创建深层副本   对象:

def deepcopy(o)
  Marshal.load(Marshal.dump(o))
end
     

[...]

     

... Marshal.dumpMarshal.load使用的二进制格式是   依赖于版本,并且不保证更新版本的Ruby   能够读取旧版本Ruby编写的编组对象。

     

[...]

     

请注意文件和I / O流,以及方法和绑定   物体,太动态,无法编组;没有可靠的   恢复状态的方法。

     

[...]

     

不要制作阵列的防御性深层副本,而是打电话   to_enum就可以了,并传递生成的枚举数而不是数组   本身。实际上,您正在创建一个可枚举但不可变的代理   数组的对象。

答案 1 :(得分:1)

忘记编组。 deep_dive gem将解决您的问题。

https://rubygems.org/gems/deep_dive

答案 2 :(得分:0)

为什么你不能使用这样的东西:

new_item = Item.new(old_item.attributes)
new_item.save!

这会将所有属性从现有项目复制到新项目,而不会出现问题。如果您有其他对象,则可以单独复制它们。

我认为这是复制对象的最快捷方式