web-dev-qa-db-ja.com

Rubyでオブジェクトのディープコピーを作成する方法

ディープコピーオペレーターの作成に関するいくつかの異なる方法と投稿をいくつか検索しました。

Rubyでオブジェクトをディープコピーするための迅速で簡単な(組み込みの)方法はありますか?フィールドは配列またはハッシュではありません。

Ruby 1.9.2。

50
B Seven

ディープコピーはVanilla Rubyに組み込まれていませんが、オブジェクトをマーシャリングおよびアンマーシャリングすることでハッキングできます。

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

65
Alex Peattie

Rubyオブジェクトのディープクローンを実行するためのネイティブ実装を作成しました。

マーシャルアプローチよりも約6〜7倍高速です。

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

このプロジェクトはもう保守されていないことに注意してください( 2017 での最後のコミット、報告されている issues

16
user2256822

Railsには、オブジェクトの詳細コピーを返すdeep_dupという名前の再帰メソッドがあり、dupおよびcloneとは反対に、複合オブジェクト(配列/ハッシュ配列/ハッシュ)。次のように簡単です:

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

Rubyオブジェクトのディープクローンを実行するネイティブ実装があります: Ruby_deep_clone

Gemでインストールします。

gem install Ruby_deep_clone

使用例:

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

これは、マーシャルアプローチの約6〜7倍の速度で、凍結オブジェクトでイベントが機能します。

このプロジェクトはもう保守されていないことに注意してください( 2017 での最後のコミット、報告されている issues

6
Mat

これには重複したgemを使用できます。

それは小さな純粋なRuby gemであり、オブジェクトを再帰的に複製することができます。新しい複製へのオブジェクト参照も複製します。

require 'duplicate'
duplicate('target object')

https://rubygems.org/gems/duplicate

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

3
Adam Luzsi

ネイティブのRuby=コアではなく、 ディープクローン メソッドではなく、多くの砂糖を追加するActiveSupport gemを使用することをお勧めします。

追加されたメソッドの詳細については、 documentation をご覧ください。

2
Noman Ur Rehman

自動ディープクローンは常に必要なものではありません。多くの場合、選択したいくつかの属性を定義してディープクローンを作成する必要があります。これを行う柔軟な方法は、initialize_copyinitialize_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/

2
lulalala

また、deep_diveも確認してください。これにより、オブジェクトグラフのディープコピーを制御できます。

https://rubygems.org/gems/deep_dive

1
flajann

あなたは本当にこれのために宝石を必要としません。これは、Gemのオーバーヘッドに見合うだけの価値はありませんが、これほど簡単なことはありません。

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
0