Подтвердить что ты не робот

Как создать глубокую копию объекта в Ruby?

Я искал несколько разных методов и сообщений о создании оператора глубокой копии.

Есть ли быстрый и простой (встроенный) способ для глубоких копий объектов в Ruby? Поля не являются массивами или хешами.

Работа в Ruby 1.9.2.

4b9b3361

Ответ 1

Глубокая копия не встроена в ванильный рубин, но вы можете взломать ее, маршируя и раскручивая объект:

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

Ответ 2

Я создал нативную реализацию для выполнения глубоких клонов объектов ruby.

Это примерно в 6-7 раз быстрее, чем подход маршала.

https://github.com/balmma/ruby-deepclone

Обратите внимание, что этот проект больше не поддерживается (последний коммит в 2017 году, есть сообщения о проблемах)

Ответ 3

Существует нативная реализация для выполнения глубоких клонов объектов ruby: ruby_deep_clone

Установите его с помощью gem:

gem install ruby_deep_clone

Пример использования:

require "deep_clone"
object = SomeComplexClass.new()
cloned_object = DeepClone.clone(object)

Это примерно в 6-7 раз быстрее, чем подход маршала, и событие работает с замороженными объектами.

Обратите внимание, что этот проект больше не поддерживается (последний коммит в 2017 году, есть сообщения о проблемах)

Ответ 4

Rails имеет рекурсивный метод с именем deep_dup, который вернет глубокую копию объекта и, напротив, dup и clone, работает даже на составных объектах (массив/хэш массивов/хэшей). Это легко:

def deep_dup
  map { |it| it.deep_dup }
end

Ответ 5

Вы можете использовать для этого дубликат драгоценности.

Это небольшой чистый рубиновый камень, способный рекурсивно дублировать объект Он также дублирует ссылки на объекты на новое дублирование.

require 'duplicate'
duplicate('target object')

https://rubygems.org/gems/duplicate

https://github.com/adamluzsi/duplicate.rb

Ответ 6

Я бы посоветовал использовать массив ActiveSupport, который добавляет много сахара в ваше родное ядро ​​Ruby, а не только метод глубокого клонирования.

Более подробную информацию о добавленных методах можно найти в документации.

Ответ 7

Автоматический глубокий клон - это не всегда то, что вы хотите. Часто вам нужно определить несколько атрибутов для глубокого клонирования. Гибкий способ сделать это - реализовать методы 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/

Ответ 8

Также проверьте deep_dive. Это позволяет выполнять контролируемые глубинные копии графиков объектов.

https://rubygems.org/gems/deep_dive

Ответ 9

Вам действительно не нужен драгоценный камень для этого. Это не может быть намного проще, чем это, что не стоит затрат на драгоценный камень!

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