在Ruby 1.9中复制对象和子对象

在Ruby 1.9中复制对象和子对象,ruby,Ruby,我的应用程序中有一个KillerSudoku类 每个实例在@cells中有许多单元格,在@zones中有许多区域,依此类推 有没有一种方法可以轻松复制一个对象(数独)复制它的所有“子对象”,也就是说,我希望我的副本中有可以修改的单元格和区域,而无需修改以前的数独?假设所有部分都是,并且你想要一个完全深度的克隆: class Object # This doesn't have to be on Object; it could be on KillerSudoku instead def

我的应用程序中有一个
KillerSudoku

每个实例在
@cells
中有许多单元格,在
@zones
中有许多区域,依此类推


有没有一种方法可以轻松复制一个对象(数独)复制它的所有“子对象”,也就是说,我希望我的副本中有可以修改的单元格和区域,而无需修改以前的数独?

假设所有部分都是,并且你想要一个完全深度的克隆:

class Object
  # This doesn't have to be on Object; it could be on KillerSudoku instead
  def deep_clone
    Marshal.load(Marshal.dump(self))
  end
end
在行动中看到:

class KillerSudoku
  attr_accessor :cells
end

ks1 = KillerSudoku.new
ks1.cells = ["one",2,3]

ks2 = ks1.deep_clone
ks2.cells.pop
ks2.cells.first.reverse!

p ks1.cells, ks2.cells
#=> ["one", 2, 3]
#=> ["eno", 2]           # New array with all instance values being uniq, too
ks1 = KillerSudoku.new
ks1.cells = ["one",2,3]

ks2 = ks1.clone
ks2.cells.pop
ks2.cells.first.reverse!

p ks1.cells, ks2.cells
#=> ["eno", 2, 3]
#=> ["eno", 2]           # New array that references all the same objects
从文档中可以看出,如果您的结构中存在以下任何一项,则上述内容将不起作用:

  • 匿名
    模块

  • 与系统相关的对象(例如
    Dir
    File::Stat
    IO
    文件
    套接字
    ,等等)

  • 匹配数据
    数据
    方法
    取消绑定方法
    过程
    线程
    线程组
    继续

  • 定义单例方法的对象


如上所述,这是一个真正的深度克隆,甚至字符串也成为新实例。如果希望克隆单元格和分区的数组,但所有值仍引用相同的对象,则需要使用
初始化\u复制
自定义
dup
克隆
的操作:

class KillerSudoku
  attr_accessor :cells
  def initialize_copy(old)
    self.cells = old.cells.dup
  end
end
在行动中看到:

class KillerSudoku
  attr_accessor :cells
end

ks1 = KillerSudoku.new
ks1.cells = ["one",2,3]

ks2 = ks1.deep_clone
ks2.cells.pop
ks2.cells.first.reverse!

p ks1.cells, ks2.cells
#=> ["one", 2, 3]
#=> ["eno", 2]           # New array with all instance values being uniq, too
ks1 = KillerSudoku.new
ks1.cells = ["one",2,3]

ks2 = ks1.clone
ks2.cells.pop
ks2.cells.first.reverse!

p ks1.cells, ks2.cells
#=> ["eno", 2, 3]
#=> ["eno", 2]           # New array that references all the same objects

我添加了一个替代实现,具体取决于您真正想要克隆的深度。有一种观点认为,最好定义
initialize\u copy
方法来实现特定于类的复制行为,而不是覆盖
dup
clone
。它们都会激活
initialize\u copy
。下面是关于这个问题的讨论。
Marshal::load(Marshal.dump(foo))
可以工作,但可能会导致数据库模型出现问题,因为它们可能会从数据库中重新提取。