在第一个 "once {next}" 块之后,其他相同范围的 "once" 块无法执行

After first "once {next}" block, other same-scoped "once" blocks fail to execute

我最初的计划是使用两个 once {next} 块来跳过文件中的前两行(此处将 a 模拟为多行字符串):

for "A\nB\nC\n".lines() -> $line {
    once {next}
    once {next}
    put $line;
}

但它只跳过了一次迭代而不是两次,输出如下:

B
C

而不是我的预期:

C

显然,单个 once {next} 以某种方式取消了同一范围内所有剩余的 once 块:

my $guard = 3;

loop {
    last if $guard-- <= 0;
    once { next };
    once { put 'A: once ' };
    once { put 'A: once again' };
    put 'A: many ';
}

$guard = 3;
loop {
    last if $guard-- <= 0;
    once { put 'B: once ' };
    once { next };
    once { put 'B: once again' };
    put 'B: many ';
}

$guard = 3;
loop {
    last if $guard-- <= 0;
    once { put 'C: once ' };
    once { put 'C: once again' };
    once { next };
    put 'C: many ';
}

输出:

A: many
A: many
B: once
B: many
B: many
C: once
C: once again
C: many
C: many

(此处的示例代码是 https://docs.raku.org/language/control#once 处代码的修改版本)。

这是一个错误还是我误解了once {next}

once 构造语义与闭包克隆相关联;由于 for 是根据 map 定义的,我们可以认为 for 循环的块就像一个闭包,每个循环克隆一次,并且该克隆用于所有迭代循环。 once 块的 运行 仅在第一次调用该闭包克隆时完成。也就是说,它是闭包级别的 属性,而不是 once 块本身之一。

完全相同的语义适用于 state 变量初始值设定项,它们以相同的方式定义(即,它们具有 once 语义)。因此,这也表现出相同的行为:

for "A\nB\nC\n".lines() -> $line {
    state $throwaway-a = next;
    state $throwaway-b = next; # this `next` never runs
    put $line;
}

可以选择其他语义,但是每个 once(以及每个 state 变量)指示器意味着它们中的每一个都需要一个额外的状态。

就最初的问题而言,更清晰的解决方案是:

for "A\nB\nC\n".lines().skip(2) -> $line {
    put $line;
}