如何在Perl 6中制作一个对象的独立副本?

8

我不完全理解文档,所以我尝试使用clone。看起来,如果可变类的属性存在,那么可以通过旧对象更改新对象的属性(这不是我想要的)。如何使它们(即副本和原始对象)完全分开?

class A {
  has @.a;
}

my A $x = A.new;
my A $y = A.new;

$x.a = 1, 2;

$y = $x.clone;

$x.a.push(4);
say $y.a; # [1 2 4]
1个回答

9
默认的继承自Mu的clone方法是浅复制,如所述。这意味着它只会复制对象本身,而不会复制对象引用的任何内容。覆盖clone方法以使用您首选的语义是可能的,这可能是在此处执行的最佳操作。
在执行此操作时,有一个有用的方法需要知道,那就是clone方法使用命名参数并将它们用于分配给克隆对象的属性。这值得知道,因为:
- 当覆盖clone方法时,应确保处理此项,以避免使用此功能的覆盖clone方法的用户产生惊喜。 - 当覆盖clone方法时,可以使用此项来简洁地选择克隆特定数组或散列属性。
因此,对于问题中的情况,请编写:
class A {
    has @.a;
    method clone() {
        callwith(:@!a, |%_)
    }
}

将会输出[1 2],正如所需。它是如何工作的呢?
- |%_ 只是将调用此clone方法的任何微调传递给下一个对象。 - :@!aa => @!a 的简写。 - callwith 调用了继承的 clone(在这种情况下是从 Mu 继承的)。 - 对目标对象上的 @!a 使用赋值而不是绑定语义(就像在对象构造期间一样),从而导致数组的副本。
这个快捷方式也适用于哈希属性。对于包含另一个对象的属性,它看起来像这样:callsame(x => $!x.clone)

1
如果class A也有@.b,那我也应该加上:@!b吗?所以,重写clone()时,我应该明确处理所有可变属性吗? - Eugene Barsky
2
@EugeneBarsky 是的,没错;对于数组和哈希表,只需像 callsame(:@!a, :%!b, ..., |%_) 一样列出它们。 - Jonathan Worthington

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接