在 Ruby 类上定义哪种方法来为其实例提供 dup / clone?

Posted

技术标签:

【中文标题】在 Ruby 类上定义哪种方法来为其实例提供 dup / clone?【英文标题】:Which method to define on a Ruby class to provide dup / clone for its instances? 【发布时间】:2012-08-10 07:46:45 【问题描述】:

我有一个带有单个属性:contentsPointer 类,它指向MyObject 类的对象。

class MyObject
  def hello; "hello" end
end

class Pointer
  attr_reader :contents
  def initialize( cont ); @contents = cont end
  # perhaps define some more state
end

我希望我的Pointer 能够复制自己。我知道#dup 方法是默认定义的,而#clone 方法预计会被覆盖以便能够进行深拷贝。但在这里,副本不必太深。所以,我遇到的第一个难题是,我是否应该重写#dup 方法,因为我真的不想复制Pointer 的附加状态,只需创建一个指向同一个MyObject 实例的新状态?或者我应该避免覆盖#dup,因为我不是“应该”并用一种制作浅拷贝的方法覆盖#clone

我会欢迎上面的 cmets,但假设我会选择覆盖 #dup。我可以这样做:

class Pointer
  def dup; self.class.new( contents ) end
end

但在网上,我读到类似“dup 方法将调用 initialize copy 方法”之类的内容。此外,this guy 在 Ruby 中写了关于 #initialize_clone#initialize_dup#initialize_copy 的内容。这让我想知道,最好的做法可能是这样吗?

class Pointer
  def initialize_copy
    # do I don't know what
  end
end

还是这样?

class Pointer
  def initialize_dup
    # do I don't know what
  end
end

或者我应该忘记那些为迷惑初学者而写的在线咆哮,而无需担心就可以覆盖#dup

另外,我明白我可以直接调用#dup 而不定义任何自定义#dup,但是如果我想用不同的行为定义#dup

同样,同样的问题也适用于#clone - 我应该尝试定义#initialize_clone 还是只定义#clone

【问题讨论】:

请问您为什么要创建一个指针类? Ruby 的变量都已经是引用/指针了。 有时你想实现你自己的数据结构或者你想让指针做一些技巧。问题的主题不是类是指针还是其他东西,但如果你必须知道,我对 Ted Nelson 的 Zz 结构感兴趣,Ted 定义了他所谓的“游标”,所以我决定称它们为“点” “就像在 Emacs 中一样。要知道,当数据结构的规范要求时,你必须实现指针类。 【参考方案1】:

根据我的经验,重载 #initialize_copy 效果很好(从未听说过 initialize_dup 和 initialize_clone)。

原始的initialize_copy(它用原始对象的值初始化每个实例变量)可以通过super获得,所以我通常这样做:

class MyClass
  def initialize_copy(orig)
    super
    # Do custom initialization for self
  end
end

【讨论】:

与重新定义#dup相比如何?一直都好吗?重新定义#dup? 最大的不同是,当你重新定义#dup 时,'self' 是原始对象。因此,您无权访问新对象的内部状态。在#initialize_copy中是相反的 另一个不同之处:我很难学到,在 Matz 的 Ruby 实现中,一些 C 函数调用例如rb_obj_dup 直接使用而不是使用正常的方法 dispatch。 #dup 可能就是其中之一。这意味着某些标准库的东西不会调用您的#dup版本,而调用#initialize_copy 哦,当我这样做时,我查看了 MRI 中的代码。 #initialize_dup 和 #initialize_clone 确实存在,但仅限于 1.9。 非常感谢。终于有人向我澄清了这一点。

以上是关于在 Ruby 类上定义哪种方法来为其实例提供 dup / clone?的主要内容,如果未能解决你的问题,请参考以下文章

在 Ruby 中动态定义命名类

java如何获取类上的注解

IOC容器管理 bean

QML中的模型/视图 十二

如何在 Ruby on Rails 迁移中使列唯一并为其编制索引?

C++:模板实现(代码风格)