语句前缀写在语句前面,并改变它们的含义、输出或运行时间。由于它们具有特定行为,因此有时它们也特定于某些语句或语句组。

lazy§

作为语句前缀,lazy 位于任何语句之前,包括 for 循环,将执行保存到实际需要分配给它们的变量时。

my $incremented = 0;
my $var = lazy for <1 2 3 4> -> $d {
    $incremented++
};
say $incremented# OUTPUT: «0␤» 
say eager $var;   # OUTPUT: «(0 1 2 3)␤» 
say $incremented# OUTPUT: «4␤» 

$incremented 变量仅在当我们急切地评估包含延迟循环的变量 $var 时才被递增,也就是说,循环的内部部分仅在此时运行。急切性可以通过其他方式应用于变量,例如在变量上调用 .eager 方法。

my @array = lazy { (^3).map*² )  };
say @array;       # OUTPUT: «[...]␤» 
say @array.eager# OUTPUT: «[0 1 4]␤» 

此前缀也可以用在 gather 前面,使内部语句按需执行;一般来说,任何返回值的语句集都可以使用此方法变为按需执行。

eager§

eager 语句前缀将急切地返回其后语句的结果,丢弃按需执行并返回结果。

my $result := eager gather { for 1..3 { say "Hey"take $_² } };
say $result[0]; # OUTPUT: «Hey␤Hey␤Hey␤1␤» 

gather绑定到标量时隐式按需执行。但是,使用 eager 作为语句前缀,它将在循环中运行所有三个迭代,如打印的 "Hey" 所示,即使我们只请求一行中的第一个。

hyper§

for 循环将自动序列化其中使用的任何 HyperSeqRaceSeq;另一方面,hyperrace 使用(可能同时)线程来运行循环中的不同迭代

my @a = hyper for ^100_000 { .is-prime }

此代码比裸 for 快约 3 倍。但这里有几个注意事项

  • 循环内的操作应该花费足够的时间才能使线程有意义。

  • 循环内部不应该对相同的数据结构进行读写访问。让循环产生结果,并将其赋值。

  • 如果循环内部有 I/O 操作,可能会有一些争用,所以请避免它。

hyperrace 之间的主要区别在于结果的顺序。如果需要循环结果按顺序产生,请使用 hyper;如果不在乎,请使用 race

quietly§

作为前缀,quietly 会抑制它之前的所有块或语句产生的运行时警告。

sub marine() {};
quietly say ~&marine# OUTPUT: «marine␤» 
sub told-you { warn 'hey...' };
quietly { told-youwarn 'kaput!' };
warn 'Telling you now!';  # OUTPUT: «Telling you now!␤ [...] ␤» 

调用 code 上的 .Str 会产生警告。在代码前面加上 quietly 将只产生输出,而不会产生警告。

try§

如果在语句前面使用 try,它将包含其中产生的异常,并将其存储在 $! 变量中,就像 它在块前面使用时一样

try [].pop;
say $!# OUTPUT: «Cannot pop from an empty Array␤..» 

do§

do 可以用作语句前缀来消除它们之前语句的歧义;例如,如果要为 for 语句的结果赋值,则需要这样做。裸 for 会失败,但这样会起作用

my $counter = 0;
my $result = do for ^5 { $counter++ };
say $counter# OUTPUT: «5␤» 
say $result;  # OUTPUT: «(0 1 2 3 4)␤» 

do 等同于在其他情况下用括号包围语句。它可以用作具有(可能更)直接语法的替代方案。

sink§

例程的情况 一样,sink 将运行语句,丢弃结果。如果要运行一些语句以产生其产生的副作用,请使用它。

my $counter = 0;
my $result = sink for ^5 { $counter++ };
say $counter#  OUTPUT: «5␤» 
say $result;  #  OUTPUT: «(Any)␤» 

sink 语句前缀也将把 Failure 转换为异常

sub find-the-number ( Int $n where $n < 10 ) {
    if $n == 7 {
        return True;
    } else {
        fail "Not that number" ;
    }
}
for 1..^10 {
    try {
        sink find-the-number($_);
    };
    say "Found $_" unless $!;
}

在这种情况下,只有当 try 块没有捕获异常时,我们才会知道该数字已被找到。

react§

react 可用于并发程序中,以创建在发生某些事件时运行的代码块。它 与块一起工作,也可以用作语句前缀。

my Channel $KXGA .= new;
for ^100 {
    $KXGA.send( (100000..200000).pick );
}
 
my @sums = ( start react whenever $KXGA -> $number {
    say "In thread "$*THREAD.id;
    say "→ ", (^$number).sum;
} ) for ^10;
 
start { sleep 10$KXGA.close(); }
 
await @sums;

在这种情况下,reactwhenever 前面加前缀,这使得每次从通道读取数字时都会进行长时间的求和。