Rubyでディープコピー

Rubyでディープコピーをするのに目から鱗な技があります。

deep_copied = Marshal::load(Marshal::dump(target_object))
こんなことができるのもRubyのシリアライザMarshalが非常に優れていて、ほぼ全てのオブジェクトに対応しているからですが、対応し過ぎているために時に思った動作をしないことがあります。例えばディープコピー対象のオブジェクトにシングルトンオブジェクトが含まれていたらどうなると思いますか?当然といえば当然ですが、これらについてもディープコピーが取られてしまい、シングルトン性が破壊されます。

そういうときはMarshalの内部的な動作を規定するためのメソッド、_dumpと_loadをオーバーライドすればよいみたいです(Ver 1.8ではmarshal_dumpとmarshal_load)。コードの例は続きをどうぞ。

class Singleton
    def initialize
        @a = 1
        @b = 2
    end
    @@obj = Singleton::new
    def Singleton::getInstance
        return @@obj
    end
    def _dump(limit)
        Marshal::dump(self.instance_variables.collect{|var| instance_variable_get(var)}, limit)
    end
    def Singleton::_load(obj)
        vars = @@obj.instance_variables
        Marshal::load(obj).each_with_index{|value, i|
            @@obj.instance_variable_set(vars[i], value)
        }
        return @@obj
    end
    private :initialize
end

class Container
    def initialize
        @singleton_obj = Singleton::getInstance
    end
end

c = Container::new
p c
#=> #<Container:0x10196bd0 @singleton_obj=#<Singleton:0x101aca40 @b=2, @a=1>>
p Marshal::load(Marshal::dump(Container::new))
#=> #<Container:0x1018c718 @singleton_obj=#<Singleton:0x101aca40 @b=2, @a=1>>


Singletonのアロケートが変わっていないことに注目してください。

March 02, 2006 06:28 fenrir が投稿 : 固定リンク | | このエントリーを含むはてなブックマーク

コメント

コメントする