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

Chr*_*oms 8 raku

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

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

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

B
C
Run Code Online (Sandbox Code Playgroud)

而不是我所期望的:

C
Run Code Online (Sandbox Code Playgroud)

显然,单个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 ';
}
Run Code Online (Sandbox Code Playgroud)

输出:

A: many
A: many
B: once
B: many
B: many
C: once
C: once again
C: many
C: many
Run Code Online (Sandbox Code Playgroud)

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

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

Jon*_*ton 12

所述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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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