Документы Ruby дляdup
говорят:
В целом
clone
иdup
может иметь различную семантику в потомках классов. Хотя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
Так в чем же разница между этими двумя методами?
dup
и чтоclone
делает, но почему бы использовать один, а не другой.Ответы:
Подклассы могут переопределять эти методы для обеспечения различной семантики. В
Object
себе, есть два основных отличия.Сначала
clone
копирует синглтон-класс, покаdup
нет.Во-вторых,
clone
сохраняет замороженное состояние, покаdup
нет.Реализация Rubinius для этих методов часто является моим источником ответов на эти вопросы, поскольку она достаточно ясна и является достаточно совместимой реализацией Ruby.
источник
o = Object.new; class << o; A=5; end; puts ( class << o.clone; A; end ); puts ( class << o.dup; A; end )
.extend
отредактированы на исходном объекте. Так чтоObject.new.extend(Enumerable).dup.is_a?(Enumerable)
возвращает ложь.При работе с ActiveRecord также есть существенная разница:
dup
создает новый объект без его идентификатора, поэтому вы можете сохранить новый объект в базе данных, нажав.save
clone
создает новый объект с тем же идентификатором, поэтому все изменения, внесенные в этот новый объект, будут перезаписывать исходную запись при нажатии.save
источник
dup
иclone
методы на моемActiveRecord
объекте, я получаю обратный результат того , что вы упомянули в ответе. что означает, что когда я используюdup
, он создает новый объект с егоid
установкой и при использованииclone
создает объект без егоid
установки. Можете ли вы посмотреть на это еще раз и уточнить? , Thnxclone
новая запись, которая никогда не была сохранена, должна быть довольно безопасной? Могу ли я создать «шаблонный объект» таким образом и клонировать его для сохранения конкретных экземпляров?Одно из различий с замороженными предметами.
clone
Замороженного объекта также замораживают ( в то время какdup
из замороженного объекта не является).Другое отличие заключается в одноэлементных методах. Та же самая история здесь,
dup
не копирует те, ноclone
делает.источник
Оба почти идентичны, но клон делает еще одну вещь, чем dup. В клоне замороженное состояние объекта также копируется. В дупе, это всегда будет таять.
источник
Более новый документ включает хороший пример:
источник
Вы можете использовать клон для программирования на прототипах в Ruby. Класс Object в Ruby определяет как метод clone, так и метод dup. И clone, и dup создают неглубокую копию копируемого объекта; то есть переменные экземпляра объекта копируются, но не объекты, на которые они ссылаются. Я продемонстрирую пример:
Обратите внимание, что в приведенном выше примере оранжевый клон копирует состояние (то есть переменные экземпляра) объекта apple, но там, где объект apple ссылается на другие объекты (например, цвет объекта String), эти ссылки не копируются. Вместо этого яблоко и апельсин оба ссылаются на один и тот же объект! В нашем примере ссылка на строковый объект red. Когда оранжевый использует метод добавления <<, чтобы изменить существующий объект String, он изменяет строковый объект на «красный оранжевый». По сути, это также меняет apple.color, поскольку они оба указывают на один и тот же объект String.
Как примечание: оператор присваивания = назначит новый объект и, таким образом, уничтожит ссылку. Вот демонстрация:
В приведенном выше примере, когда мы присваиваем новый новый объект методу экземпляра цвета оранжевого клона, он больше не ссылается на тот же объект, что и яблоко. Следовательно, теперь мы можем изменить цветовой метод оранжевого цвета, не затрагивая цветовой метод apple, но если мы клонируем другой объект из apple, этот новый объект будет ссылаться на те же объекты в скопированных переменных экземпляра, что и на apple.
dup также создаст поверхностную копию объекта, который копирует, и если вы выполните ту же демонстрацию, показанную выше, для dup, вы увидите, что она работает точно так же. Но есть два основных различия между клоном и дупом. Во-первых, как уже упоминалось, клон копирует замороженное состояние, а dup - нет. Что это значит? Термин «замороженный» в Ruby - это эзотерический термин для неизменного, который сам по себе является номенклатурой в компьютерной науке, означая, что что-то нельзя изменить. Таким образом, замороженный объект в Ruby никак не может быть изменен; это, по сути, неизменным. Если вы попытаетесь изменить замороженный объект, Ruby вызовет исключение RuntimeError. Поскольку клон копирует замороженное состояние, если вы попытаетесь изменить клонированный объект, это вызовет исключение RuntimeError. И наоборот, поскольку dup не копирует замороженное состояние,
Во-вторых, и, что более интересно, клон копирует синглтон-класс (и, следовательно, его методы)! Это очень полезно, если вы хотите заняться программированием на основе прототипов в Ruby. Сначала давайте покажем, что действительно синглтон-методы копируются с помощью клона, а затем мы можем применить его на примере программирования на основе прототипов в Ruby.
Как видите, синглтон-класс экземпляра объекта Fruit копируется в клон. И, следовательно, клонированный объект имеет доступ к одноэлементному методу: seeded ?. Но в случае с dup это не так:
Теперь в программировании на основе прототипов у вас нет классов, которые расширяют другие классы, а затем создают экземпляры классов, чьи методы являются производными от родительского класса, который служит планом. Вместо этого у вас есть базовый объект, а затем вы создаете новый объект из объекта с копированием его методов и состояния (конечно, поскольку мы делаем мелкие копии с помощью клона, любые объекты, на которые ссылаются переменные экземпляра, будут совместно использоваться, как в JavaScript прототипы). Затем вы можете заполнить или изменить состояние объекта, заполнив детали клонированных методов. В приведенном ниже примере у нас есть базовый фруктовый объект. У всех фруктов есть семена, поэтому мы создаем метод number_of_seeds. Но у яблок есть одно семя, и поэтому мы создаем клон и заполняем детали. Теперь, когда мы клонируем яблоко, мы не только клонировали методы, но и клонировали государство! Помните, что клон делает поверхностную копию состояния (переменные экземпляра). И поэтому, когда мы клонируем яблоко, чтобы получить red_apple, у red_apple автоматически будет 1 семя! Вы можете думать о red_apple как об объекте, который наследуется от Apple, который, в свою очередь, наследуется от Fruit. Следовательно, именно поэтому я использовал заглавные буквы Fruit и Apple. Мы покончили с различием между классами и объектами благодаря клону.
Конечно, у нас может быть метод конструктора в программировании на основе прототипов:
В конечном счете, используя клон, вы можете получить нечто похожее на поведение прототипа JavaScript.
источник