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

Bor*_*cky 9 ruby clone dup

我有一个Pointer具有单个属性的类:contents,它指向类的对象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
Run Code Online (Sandbox Code Playgroud)

我希望我Pointer能够复制自己.我知道该#dup方法是默认定义的,而#clone方法应该被覆盖以便能够进行深层复制.但在这里,副本不必太深.所以,#dup我遇到的第一个困境是,我应该覆盖方法,因为我真的不想复制我的附加状态Pointer,只是创建一个指向同一个MyObject实例的新状态?或者我应该避免过度使用#dup,因为我不是"应该"并#clone用一种制作浅拷贝的方法来覆盖?

我欢迎对上述内容发表评论,但我要说我会选择覆盖#dup.我能做到这一点:

class Pointer
  def dup; self.class.new( contents ) end
end
Run Code Online (Sandbox Code Playgroud)

但是在网上,我读过类似" dup方法将调用初始化复制方法"的内容.此外,这家伙写的#initialize_clone,#initialize_dup#initialize_copy在Ruby中.这让我感到疑惑,是最好的做法也许是这样的?

class Pointer
  def initialize_copy
    # do I don't know what
  end
end
Run Code Online (Sandbox Code Playgroud)

或者像这样?

class Pointer
  def initialize_dup
    # do I don't know what
  end
end
Run Code Online (Sandbox Code Playgroud)

或者,我是否应该忘记为了让初学者#dup感到困惑而写的网上咆哮,并且不顾一切地排在首位?

另外,我确实理解我可以在#dup不定义任何自定义的情况下调用#dup,但如果我想#dup用不同的行为定义怎么办?

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

syl*_*eux 17

根据我的经验,重载#initialize_copy工作正常(从未听说过initialize_dup和initialize_clone).

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

class MyClass
  def initialize_copy(orig)
    super
    # Do custom initialization for self
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 最大的区别在于,当你重新定义#dup时,'self'是原始对象.因此,您无权访问新对象的内部状态.这是#initialize_copy的另一种方式 (3认同)
  • 还有一个区别:我学到了很难的方法,在Matz的Ruby实现中,一些C函数直接调用例如rb_obj_dup而不是使用普通的方法调度.#dup可能就是其中之一.这意味着一些标准库的东西*不会*调用你的#dup版本,而它*会*调用#initialize_copy (2认同)