Ruby的dup和clone方法有什么区别?

cal*_*500 213 ruby clone dup

Ruby的文档的dup说:

在一般情况下,clonedup可能在派生类不同的语义.虽然clone用于复制对象(包括其内部状态),但dup通常使用后代对象的类来创建新实例.

但是当我做一些测试时,我发现它们实际上是相同的:

class Test
   attr_accessor :x
end

x = Test.new
x.x = 7
y = x.dup
z = x.clone
y.x => 7
z.x => 7
Run Code Online (Sandbox Code Playgroud)

那么这两种方法有什么区别?

Jer*_*man 296

子类可以重写这些方法以提供不同的语义.在Object本身,有两个关键区别.

首先,clone复制单例类,而dup不是.

o = Object.new
def o.foo
  42
end

o.dup.foo   # raises NoMethodError
o.clone.foo # returns 42
Run Code Online (Sandbox Code Playgroud)

第二,clone保留冷冻状态,而不保留dup.

class Foo
  attr_accessor :bar
end
o = Foo.new
o.freeze

o.dup.bar = 10   # succeeds
o.clone.bar = 10 # raises RuntimeError
Run Code Online (Sandbox Code Playgroud)

这些方法Rubinius实现 通常是我对这些问题的答案的来源,因为它非常清楚,并且是一个相当兼容的Ruby实现.

  • 如果有人试图再次改变它:"单例类",这是Ruby中明确定义的术语,不仅包括单例*方法*,还包括在单例类上定义的任何常量.考虑:`o = Object.new; class << o; A = 5; 结束; puts(class << o.clone; A; end); puts(class << o.dup; A; end)`. (15认同)
  • 很好的答案,然后是一个很好的评论,但它引导我进行疯狂的追逐,以了解语法.这将有助于那些可能也会感到困惑的其他人:http://www.devalot.com/articles/2008/09/ruby-singleton (3认同)

jva*_*nen 186

处理ActiveRecord时也存在显着差异:

dup 创建一个没有设置id的新对象,这样你就可以通过点击将新对象保存到数据库中 .save

category2 = category.dup
#=> #<Category id: nil, name: "Favorites"> 
Run Code Online (Sandbox Code Playgroud)

clone 创建一个具有相同id的新对象,因此对该新对象所做的所有更改都将覆盖原始记录(如果按下) .save

category2 = category.clone
#=> #<Category id: 1, name: "Favorites">
Run Code Online (Sandbox Code Playgroud)

  • 这个答案是IMO最重要的实用信息......其他答案都是关于esoterica,而这个答案确定了一个关键的实际差异. (43认同)
  • 以上是ActiveRecord特有的; 标准Ruby中的区别更为微妙. (37认同)

Jon*_*eim 30

一个区别是冷冻物体.在clone一个冻结对象的也冻结(而dup冻结对象的不是).

class Test
  attr_accessor :x
end
x = Test.new
x.x = 7
x.freeze
y = x.dup
z = x.clone
y.x = 5 => 5
z.x = 5 => TypeError: can't modify frozen object
Run Code Online (Sandbox Code Playgroud)

另一个区别在于单身方法.同样的故事,dup不会复制那些,但clone确实如此.

def x.cool_method
  puts "Goodbye Space!"
end
y = x.dup
z = x.clone
y.cool_method => NoMethodError: undefined method `cool_method'
z.cool_method => Goodbye Space!
Run Code Online (Sandbox Code Playgroud)


Xav*_*rac 5

新的文档包含一个很好的例子:

class Klass
  attr_accessor :str
end

module Foo
  def foo; 'foo'; end
end

s1 = Klass.new #=> #<Klass:0x401b3a38>
s1.extend(Foo) #=> #<Klass:0x401b3a38>
s1.foo #=> "foo"

s2 = s1.clone #=> #<Klass:0x401b3a38>
s2.foo #=> "foo"

s3 = s1.dup #=> #<Klass:0x401b3a38>
s3.foo #=> NoMethodError: undefined method `foo' for #<Klass:0x401b3a38>
Run Code Online (Sandbox Code Playgroud)