В чем разница между методами 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