12

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

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

我还需要一个add返回 aRect但不操作的方法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 中不存在这样的基本功能?请不要告诉我我可以反转addand add!,让add做这项工作,然后add!调用它。

4

3 回答 3

6

我不确定为什么 Ruby 中没有深拷贝方法,但我会尝试根据我能找到的信息做出有根据的猜测(请参阅行下方的链接和引号)。

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

如您所知,使用Marshal.dumpandMarshal.load是目前推荐的方法。这也是 Programming Ruby 推荐的方法(参见下面的摘录)。

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


相关信息

这是comp.lang.ruby 上的一个讨论,可能会对此有所了解。这里有一些相关讨论的另一个答案,但这一切都回到了使用Marshal.

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

[…]

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

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

[…]

... 和使用的二进制格式Marshal.dumpMarshal.load版本有关,较新版本的 Ruby 不能保证能够读取由旧版本 Ruby 编写的编组对象。

[…]

请注意,文件和 I/O 流以及 Method 和 Binding 对象过于动态而无法编组;没有可靠的方法来恢复他们的状态。

[…]

与其制作数组的防御性深层副本,不如调用 to_enum它,并传递结果枚举器而不是数组本身。实际上,您正在为您的数组创建一个可枚举但不可变的代理对象。

于 2013-07-28T22:09:29.623 回答
2

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

https://rubygems.org/gems/deep_dive

于 2014-01-19T19:48:47.507 回答
0

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

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

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

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

于 2015-03-17T19:50:54.507 回答