在角色迭代器中§

有关方法 pull-one 的主要文档,请参阅上下文

method pull-one(Iterator:D: --> Mu)

此方法存根确保实现 Iterator 角色的类提供名为 pull-one 的方法。

pull-one 方法应该在可能的情况下生成并返回下一个值,如果无法生成更多值,则返回哨兵值 IterationEnd

my $i = (1 .. 3).iterator;
say $i.pull-one;       # OUTPUT: «1␤» 
say $i.pull-one;       # OUTPUT: «2␤» 
say $i.pull-one;       # OUTPUT: «3␤» 
say $i.pull-one.raku;  # OUTPUT: «IterationEnd␤»

作为其用法的更具说明性的示例,这里有一个倒计时迭代器以及 for 循环的简化子例程重新实现。

# works the same as (10 ... 1, 'lift off') 
class CountDown does Iterator {
    has Int:D $!current = 10;
 
    method pull-one ( --> Mu ) {
        my $result = $!current--;
        if $result ==  0 { return 'lift off' }
        if $result == -1 { return IterationEnd }
 
        # calling .pull-one again after it returns IterationEnd is undefined 
        if $result <= -2 {
            # so for fun we will give them nonsense data 
            return (1..10).pick;
        }
 
        return $result;
    }
}
 
sub forIterable:D $sequence&do --> Nil ) {
    my Iterator:D $iterator = $sequence.iterator;
 
    loop {
        # must bind the result so that =:= works 
        my Mu $pulled := $iterator.pull-one;
 
        # always check the result and make sure that .pull-one 
        # is not called again after it returns IterationEnd 
        if $pulled =:= IterationEnd { last }
 
        do$pulled );
    }
}
 
forSeq.new(CountDown.new), &say );  # OUTPUT: «10␤9␤8␤7␤6␤5␤4␤3␤2␤1␤lift off␤»

更惯用的做法是使用 whileuntil,以及一个无符号变量。

until IterationEnd =:= (my \pulled = $iterator.pull-one{
    dopulled );
}