Я искал несколько разных методов и сообщений о создании оператора глубокой копии.
Есть ли быстрый и простой (встроенный) способ для глубоких копий объектов в Ruby? Поля не являются массивами или хешами.
Работа в Ruby 1.9.2.
Я искал несколько разных методов и сообщений о создании оператора глубокой копии.
Есть ли быстрый и простой (встроенный) способ для глубоких копий объектов в Ruby? Поля не являются массивами или хешами.
Работа в Ruby 1.9.2.
Глубокая копия не встроена в ванильный рубин, но вы можете взломать ее, маршируя и раскручивая объект:
Marshal.load(Marshal.dump(@object))
Это не идеально, и не будет работать для всех объектов. Более надежный метод:
class Object
def deep_clone
return @deep_cloning_obj if @deep_cloning
@deep_cloning_obj = clone
@deep_cloning_obj.instance_variables.each do |var|
val = @deep_cloning_obj.instance_variable_get(var)
begin
@deep_cloning = true
val = val.deep_clone
rescue TypeError
next
ensure
@deep_cloning = false
end
@deep_cloning_obj.instance_variable_set(var, val)
end
deep_cloning_obj = @deep_cloning_obj
@deep_cloning_obj = nil
deep_cloning_obj
end
end
Источник:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/43424
Я создал нативную реализацию для выполнения глубоких клонов объектов ruby.
Это примерно в 6-7 раз быстрее, чем подход маршала.
https://github.com/balmma/ruby-deepclone
Обратите внимание, что этот проект больше не поддерживается (последний коммит в 2017 году, есть сообщения о проблемах)
Существует нативная реализация для выполнения глубоких клонов объектов ruby: ruby_deep_clone
Установите его с помощью gem:
gem install ruby_deep_clone
Пример использования:
require "deep_clone"
object = SomeComplexClass.new()
cloned_object = DeepClone.clone(object)
Это примерно в 6-7 раз быстрее, чем подход маршала, и событие работает с замороженными объектами.
Обратите внимание, что этот проект больше не поддерживается (последний коммит в 2017 году, есть сообщения о проблемах)
Rails имеет рекурсивный метод с именем deep_dup
, который вернет глубокую копию объекта и, напротив, dup
и clone
, работает даже на составных объектах (массив/хэш массивов/хэшей).
Это легко:
def deep_dup
map { |it| it.deep_dup }
end
Вы можете использовать для этого дубликат драгоценности.
Это небольшой чистый рубиновый камень, способный рекурсивно дублировать объект Он также дублирует ссылки на объекты на новое дублирование.
require 'duplicate'
duplicate('target object')
Я бы посоветовал использовать массив ActiveSupport, который добавляет много сахара в ваше родное ядро Ruby, а не только метод глубокого клонирования.
Более подробную информацию о добавленных методах можно найти в документации.
Автоматический глубокий клон - это не всегда то, что вы хотите. Часто вам нужно определить несколько атрибутов для глубокого клонирования. Гибкий способ сделать это - реализовать методы initialize_copy
, initialize_dup
и initialize_clone
.
Если у вас есть класс:
class Foo
attr_accessor :a, :b
end
и вы только хотите только глубокий клон :b
, вы переопределите метод initialize_*
:
class Foo
attr_accessor :a, :b
def initialize_dup(source)
@b = @b.dup
super
end
end
Конечно, если вы хотите, чтобы @b
также глубоко клонировал некоторые свои атрибуты, вы делаете то же самое в классе b.
Rails делает это (см. Https://github.com/rails/rails/blob/0951306ca5edbaec10edf3440d5ba11062a4f2e5/activemodel/lib/active_model/errors.rb#L78)
Для более полного объяснения я узнал его здесь из этого сообщения https://aaronlasseigne.com/2014/07/20/know-ruby-clone-and-dup/
Также проверьте deep_dive. Это позволяет выполнять контролируемые глубинные копии графиков объектов.
Вам действительно не нужен драгоценный камень для этого. Это не может быть намного проще, чем это, что не стоит затрат на драгоценный камень!
def deep_clone(obj)
obj.clone.tap do |new_obj|
new_obj.each do |key, val|
new_obj[key] = deep_clone(val) if val.is_a?(Hash)
end
end
end