在 Raku 中克隆对象

Cloning Objects in Raku

在 raku 中克隆对象的最佳方法是什么?我知道存在克隆方法,但它似乎不适用于嵌套对象。

例如,在这个脚本中:

#!/usr/bin/env perl6

class Group {
    has Int @!group = Array[Int].new;

    method add-item(Int $int) {
        @!group.push($int);
    }

    method print {
        say @!group;
    }
}

class GroupOfGroups {
    has Group @!multi-group = Array[Group].new;

    method add-group(Group $group) {
        @!multi-group.push($group);
    }

    method print {
        for ^@!multi-group.elems -> $i {
            @!multi-group[$i].print;
        }
    }
}

my $group = Group.new;
$group.add-item(1);
$group.add-item(2);
$group.add-item(3);

my $group-of-groups = GroupOfGroups.new;
$group-of-groups.add-group($group.clone);
$group.add-item(4);
$group.add-item(5);
$group.add-item(6);

$group-of-groups.add-group($group.clone);

$group-of-groups.print;

输出为:

[1 2 3 4 5 6]
[1 2 3 4 5 6]

但我期待它是:

[1 2 3]
[1 2 3 4 5 6]

我不会使用 clone 以外的任何东西来克隆对象。 clone 是由 Mu 定义的原型方法,但在这种情况下由其子类型来实现其行为,因为克隆对象确实克隆了数组属性,但不是以您想要的方式。因此,您可以编写自己的 clone multis,其行为与您期望的一样:

# Group
multi method clone(::?CLASS:D: --> ::?CLASS:D) {
    my ::?CLASS:D $clone .= new;
    $clone.add-item: .clone for @!group;
    $clone
}

# GroupOfGroups
multi method clone(::?CLASS:D: --> ::?CLASS:D) {
    my ::?CLASS:D $clone .= new;
    $clone.add-group: .clone for @!multi-group;
    $clone
}

::?CLASS 是一个符号,当在 classes 中使用时,它是 class 本身的别名,:D 将类型限制为仅实例.

你好@julio,仔细阅读 docs 让我想到了这个......很有魅力:

method clone { nextwith :foo(@!foo.clone), :bar(%!bar.clone), |%_  }

(这也帮助我理解了深度克隆的“受限”语言帮助背后的合理性)