В чем разница между методами DUP Ruby и clone?
на Ruby docs для dup
говорят:
В общем,
clone
иdup
может иметь различную семантику в подчиненных классах. В то время какclone
используется для дублирования объекта, включая его внутреннее состояние,dup
обычно использует класс объекта descendent для создания нового экземпляра.
но когда я делаю какой-то тест, я обнаружил, что они на самом деле одинаковы:
class Test
attr_accessor :x
end
x = Test.new
x.x = 7
y = x.dup
z = x.clone
y.x => 7
z.x => 7
Итак, каковы различия между этими двумя методы?
5 ответов
подклассы могут переопределять эти методы для обеспечения различной семантики. В Object
сам по себе, есть два ключевых отличия.
во-первых,clone
копирует класс singleton, в то время как dup
нет.
o = Object.new
def o.foo
42
end
o.dup.foo # raises NoMethodError
o.clone.foo # returns 42
во-вторых,clone
сохраняет замороженное состояние, в то время как dup
нет.
class Foo
attr_accessor :bar
end
o = Foo.new
o.freeze
o.dup.bar = 10 # succeeds
o.clone.bar = 10 # raises RuntimeError
на реализация Rubinius для этих методов часто является моим источником для ответов на эти вопросы, так как это довольно ясно и довольно совместимая реализация Руби.
при работе с ActiveRecord есть существенная разница:
dup
создает новый объект без его идентификатора, поэтому вы можете сохранить новый объект в базе данных, нажав .save
category2 = category.dup
#=> #<Category id: nil, name: "Favorites">
clone
создает новый объект с тем же идентификатором, поэтому все изменения, внесенные в этот новый объект, перезапишут исходную запись при нажатии .save
category2 = category.clone
#=> #<Category id: 1, name: "Favorites">
одно отличие с замороженными объектами. The 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
другое отличие-с Singleton-методы. Та же история и здесь,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!
на новый doc включает в себя хороший пример:
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>
оба почти идентичны, но клон делает еще одну вещь, чем dup. В clone также копируется замороженное состояние объекта. В dup он всегда будет оттаивать.
f = 'Frozen'.freeze
=> "Frozen"
f.frozen?
=> true
f.clone.frozen?
=> true
f.dup.frozen?
=> false