6

执行一个班轮从标准输入一次处理 CSV 一行:

perl6 -ne 'my @a; $_.split(",").kv.map: {@a[$^k]+=$^v}; say @a; ENTER {say "ENTER"}; BEGIN {say "BEGIN"}; LEAVE {say "LEAVE"}; END {say "END"}';

输入:

1,1
1,1
^D

给出以下输出:

BEGIN
ENTER
1,1
[1 1]
1,1
[2 2]
LEAVE
END

在这里,我们可以看到一个 liner 不是多次执行的块,因为 ENTER 和 LEAVE 相位器只执行一次。

这是有道理的,因为变量 @a 正在累积。如果一个衬里是一个块,则每次都会重置 @a 的值。

我的问题是主题变量 $_ 是如何更新的?主题变量是一个 Str (至少 $_.^name 是这么说的)。它的值如何在不重新进入区块的情况下更新?

我错过了什么?

4

3 回答 3

9

当您添加-n它时,它会在您的代码周围添加一个for循环。

你认为它增加了一个这样的:

for lines() {
  # Your code here
}

编译器只是添加抽象语法树节点以进行循环,而不实际添加块。

(
   # Your code here
) for lines()

(它可能被解释为一个错误。)

让它像第一个一样工作:

(             # -n adds this

  -> $_ {     # <-- add this

              # Your code here

  }( $_ )     # <-- add this

) for lines() # -n adds this

我尝试只添加一个裸块,但编译器添加循环的方式导致它不起作用。


一般来说ENTER,andLEAVE的作用域是一个块{},但如果没有块,它们的作用域也是“<em>file”。

ENTER say 'ENTER file';
LEAVE say 'LEAVE file';
{
  ENTER say '  ENTER block';
  LEAVE say '  LEAVE block';
}
ENTER file
  ENTER block
  LEAVE block
LEAVE file

由于您的代码中没有块,因此所有内容都局限于“<em>文件”。

于 2019-01-25T15:06:53.663 回答
3

-n 命令行参数在您的程序周围放置一个循环,

for $*ARGFILES.lines {
    # Program block given on command line
}

而您使用的程序执行阶段器BEGINEND)在编译时或程序块完成后运行一次,因此它们在运行时不会成为循环的一部分。

ENTER块移相器将在每个块进入时间运行,而LEAVE块移相器将在每个块退出时间运行。for因此,这些移相器将为循环中读取的每一行运行。

于 2019-01-25T06:32:12.650 回答
1

更新——乐道 2020.10

运行您的原始累加器代码(使用-nelinewise 标志)会得到以下结果。注意“final”这个词是如何出现在每一行的:

~$ perl6 -ne 'my @a; $_.split(",").kv.map: {@a[$^k]+=$^v}; say @a, " final"; ENTER {say "ENTER"}; BEGIN {say "BEGIN"}; LEAVE {say "LEAVE"}; END {say "END"};' drclaw.txt
BEGIN
ENTER
[1 1] final
[2 3] final
[3 6] final
LEAVE
END

-ne下面,使用标志背靠背运行基本上重复的脚本会产生一个有趣的结果。BEGIN, ENTER, LEAVE, 并END显示在完全相同的位置,按照每次调用一次的顺序重复:

~$ perl6 -ne 'my @a; .split(",").kv.map: {@a[$^k]+=$^v}; say @a, " final_a";  ENTER {say "ENTER"}; BEGIN {say "BEGIN"}; LEAVE {say "LEAVE"}; END {say "END"};  my @b; .split(",").kv.map: {@b[$^k]+=$^v}; say @b, " final_b"; ENTER {say "ENTER"}; BEGIN {say "BEGIN"}; LEAVE {say "LEAVE"}; END {say "END"};' drclaw.txt
BEGIN
BEGIN
ENTER
ENTER
[1 1] final_a
[1 1] final_b
[2 3] final_a
[2 3] final_b
[3 6] final_a
[3 6] final_b
LEAVE
LEAVE
END
END

但是,删除-ne下面的标志可以让您for lines() {...}在 Raku 代码本身内运行一个循环(单个脚本,而不是背靠背重复)。这个结果似乎更符合您的预期:

~$ perl6 -e 'my @a; for lines() {.split(",").kv.map: {@a[$^k]+=$^v};}; say @a, " final"; ENTER {say "ENTER"}; BEGIN {say "BEGIN"}; LEAVE {say "LEAVE"}; END {say "END"};' drclaw.txt
BEGIN
ENTER
[3 6] final
LEAVE
END

我认为对您的问题的简短回答是 Phasers 尊重块/循环语义,但在脚本方面受限于他们将向实施者报告多少次(显然每次调用只有一次)。但最终的区别在于,与没有命令行标志的内部循环相比,命令行标志对用户的返回是逐行的。-nefor lines() {...}-ne

最后,您始终可以使用中缀运算符强制重新加载$_主题变量。andthen也许这就是您一直在寻找的:

~$ perl6 -e 'my @a; for lines() {.split(",").kv.map: {@a[$^k]+=$^v} andthen $_.say }; say @a, " final"; ENTER {say "ENTER"}; BEGIN {say "BEGIN"}; LEAVE {say "LEAVE"}; END {say "END"};' drclaw.txt
BEGIN
ENTER
(1 1)
(2 3)
(3 6)
[3 6] final
LEAVE
END

[正在分析的测试文件,如下]。

~$ cat drclaw.txt
1,1
1,2
1,3

https://docs.raku.org/language/operators#index-entry-andthen

于 2021-04-13T20:50:04.320 回答