54 votes

Comment créer une copie profonde d'un objet en Ruby ?

J'ai fait quelques recherches et j'ai trouvé différentes méthodes et articles sur la création d'un opérateur de copie profonde.

Existe-t-il un moyen rapide et facile (intégré) de copier profondément des objets en Ruby ? Les champs ne sont pas des tableaux ou des hachages.

Travaillant en Ruby 1.9.2.

67voto

Alex Peattie Points 8754

La copie profonde n'est pas intégrée à Ruby, mais vous pouvez la pirater en marshallant et démarshallant l'objet :

Marshal.load(Marshal.dump(@object))

Cette méthode n'est cependant pas parfaite et ne fonctionne pas pour tous les objets. Une méthode plus robuste :

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

Source :

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/43424

20voto

user2256822 Points 91

J'ai créé une implémentation native pour effectuer des clones profonds d'objets rubis.

C'est environ 6 à 7 fois plus rapide que l'approche Marshal.

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

Notez que ce projet n'est plus maintenu (le dernier commit date de 2017 il y a des rapports questions )

7voto

Mat Points 21

Il existe une implémentation native pour effectuer des clones profonds d'objets rubis : ruby_deep_clone

Installez-le avec gem :

gem install ruby_deep_clone

Exemple d'utilisation :

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

Elle est environ 6 à 7 fois plus rapide que l'approche Marshal et l'événement fonctionne avec des objets gelés.

Notez que ce projet n'est plus maintenu (le dernier commit date de 2017 il y a des rapports questions )

7voto

Claudio Floreani Points 516

Rails possède une méthode récursive nommée deep_dup qui retournera une copie profonde d'un objet et, au contraire de dup et clone fonctionne même sur les objets composites (tableaux/classements de tableaux/classements). C'est aussi simple que cela :

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

3voto

lulalala Points 3895

Le clone profond automatique n'est pas toujours ce que l'on souhaite. Il est souvent nécessaire de définir quelques attributs sélectionnés pour le clonage profond. Une façon flexible de le faire est d'implémenter la fonction initialize_copy , initialize_dup et initialize_clone méthodes.

Si vous avez une classe :

class Foo
  attr_accessor :a, :b
end

et vous ne voulez que le clone profond :b vous remplacez le initialize_* méthode :

class Foo
  attr_accessor :a, :b

  def initialize_dup(source)
    @b = @b.dup
    super
  end
end

Bien sûr, si vous voulez @b pour cloner profondément certains de ses propres attributs, vous faites de même dans la classe de b.

Rails le fait (voir https://github.com/rails/rails/blob/0951306ca5edbaec10edf3440d5ba11062a4f2e5/activemodel/lib/active_model/errors.rb#L78 )

Pour une explication plus complète, je l'ai appris ici à partir de ce post https://aaronlasseigne.com/2014/07/20/know-ruby-clone-and-dup/

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X