复制对象的奇怪行为

时间:2014-11-12 21:22:14

标签: ruby deep-copy

我正在尝试深度复制一个包含3D数组的对象。但它没有按预期工作。

class A
    def initialize
        @a = [[[1]], [[2]]]
    end

    def modify3D
        @a[0][0] = @a[1][0]
    end

    def modify2D
        @a[0] = @a[1]
    end

    def dup
        copy = super
        copy.make_independent!
        copy
    end

    def make_independent!
        @a = @a.dup
    end

    def show
        print "\n#{@a}"
    end
end

a = A.new
b = a.dup
#a.modify2D
b.show
a.modify3D
b.show

在这种情况下,b由a上的modify3D调用更改。

[[[1]], [[2]]]
[[[2]], [[2]]]

如果我取消注释modify2D行,一切正常。

[[[1]], [[2]]]
[[[1]], [[2]]]

有人可以解释一下这里发生了什么吗?

1 个答案:

答案 0 :(得分:2)

您的副本不够深入。 Array#dup只复制数组本身,而不是数组元素。您最终会得到两个仍然共享相同元素的不同数组。

this answer中,我展示了如何使用marshaling进行深层复制。这种方法可以完成所有工作:

def deep_copy(o)
  Marshal.load(Marshal.dump(o))
end

deep_copy适用于任何可以封送的对象。大多数内置数据类型(Array,Hash,String和& c。)都可以编组。实例变量可以封送的任何对象本身都可以被封送。

定义了deep_copy,然后替换这一行:

b = a.dup

用这个:

b = deep_copy(a)

它应该像你期望的那样工作。