首页 > 解决方案 > 实现 AT-POS 以返回对象而不是事物列表

问题描述

我有以下课程:

class Names {
    has @!names;

    method add-name( $name ) { @!names.push($name) }

    multi method AT-POS( ::?CLASS:D: $index ) {
        my $new-names-obj = Names.new;

        for @!names[$index] -> $name {
            $new-names-obj.add-name($name);
        }

        return $new-names-obj;
    }

    method gist {
        @!names.join("\n")
    }
}

我希望能够对一个Names对象进行切片,并且返回的值应该是另一个Names对象,其元素已从原始Names对象中切出。例如:

my $original = Names.new;
$original.add-name($_) for <jonathan joseph jotaro josuke giorno>;
my $sliced-off = $original[0..2];

say $original.^name;   #=> Names
say $original;         #=> jonathan, joseph, jotaro, josuke, giorno
say $sliced-off.^name; #=> List
say $sliced-off;       #=> (jonathan joseph jotaro)

当传递一个参数时,它会按预期工作并如本答案中所述,但范围并非如此,因为AT-POS最终会被多次调用并将结果收集到一个列表中。因此,我想知道$sliced-off在使用范围时是否可以返回单个对象,而不是结果列表。

标签: objectsliceraku

解决方案


AT-POS方法旨在让对象充当Positional对象。这不是你想要的。你想要object[slice]DWIM。

实现这一目标的最佳方法是为您的对象创建一个postcircumfic:<[ ]>(多)候选者:

class A {
    method slice(@_) {
        say @_;  # just to show the principle
    }
}
sub postcircumfix:<[ ]>($object, *@indices) {
   constant &slicer = &postcircumfix:<[ ]>;
   $object ~~ A
     ?? $object.slice(@indices)
     !! slicer($object, @indices)
}

A.new[1,2,4,5];  # [1 2 4 5]

my @a = ^10;     # check if foo[] still works
say @a[1,2,4,5]; # (1 2 4 5)

为了确保保留 的常见行为,我们在编译时@a[]保存系统的值(使用 a )。然后在运行时,当对象属于正确的类时,使用给定参数调用原始版本。postcircumfix:[ ]>constantpostcircumfix:<[ ]>


推荐阅读