What's the difference between Ruby's dup a

2019-01-03 00:56发布

The Ruby docs for dup say:

In general, clone and dup may have different semantics in descendent classes. While clone is used to duplicate an object, including its internal state, dup typically uses the class of the descendent object to create the new instance.

But when I do some test I found they are actually the same:

class Test
   attr_accessor :x
end

x = Test.new
x.x = 7
y = x.dup
z = x.clone
y.x => 7
z.x => 7

So what are the differences between the two methods?

标签: ruby clone dup
5条回答
女痞
2楼-- · 2019-01-03 01:24

One difference is with frozen objects. The clone of a frozen object is also frozen (whereas a dup of a frozen object isn't).

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

Another difference is with singleton methods. Same story here, dup doesn't copy those, but clone does.

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!
查看更多
Juvenile、少年°
3楼-- · 2019-01-03 01:25

Both are nearly identical but clone does one more thing than dup. In clone, the frozen state of the object is also copied. In dup, it’ll always be thawed.

 f = 'Frozen'.freeze
  => "Frozen"
 f.frozen?
  => true 
 f.clone.frozen?
  => true
 f.dup.frozen?
  => false 
查看更多
劫难
4楼-- · 2019-01-03 01:27

When dealing with ActiveRecord there's a significant difference too:

dup creates a new object without its id being set, so you can save a new object to the database by hitting .save

category2 = category.dup
#=> #<Category id: nil, name: "Favorites"> 

clone creates a new object with the same id, so all the changes made to that new object will overwrite the original record if hitting .save

category2 = category.clone
#=> #<Category id: 1, name: "Favorites">
查看更多
不美不萌又怎样
5楼-- · 2019-01-03 01:31

Subclasses may override these methods to provide different semantics. In Object itself, there are two key differences.

First, clone copies the singleton class, while dup does not.

o = Object.new
def o.foo
  42
end

o.dup.foo   # raises NoMethodError
o.clone.foo # returns 42

Second, clone preserves the frozen state, while dup does not.

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

o.dup.bar = 10   # succeeds
o.clone.bar = 10 # raises RuntimeError

The Rubinius implementation for these methods is often my source for answers to these questions, since it is quite clear, and a fairly compliant Ruby implementation.

查看更多
趁早两清
6楼-- · 2019-01-03 01:37

The newer doc includes a good example:

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>
查看更多
登录 后发表回答