我正在尝试编写如下的紧凑行,该代码是从使用动态范围的特殊变量 $*IN 读取 STDIN 的脚本中提取的。你能建议如何正确地写这一行吗?
这个作品
for $*IN.lines() {
last when "" ;
say "VERBOSE \"$_ is the string\"";
$i=$i+1;
}
不起作用
.say "VERBOSE \"$_ is the string\"" for $*IN.lines() last when "";
错误输出:
===SORRY!=== Error while compiling /usr/share/asterisk/agi-bin/agi-t1.p6
Two terms in a row
at /usr/share/asterisk/agi-bin/agi-t1.p6:5
------> .say⏏ "Verbose \"$_\"" for $*IN.lines() last
expecting any of:
infix
infix stopper
statement end
statement modifier
statement modifier loop
最佳答案
错误消息的一般解释
===SORRY!=== Error while compiling ...
当您看到 SORRY!
,那么您就知道编译器正在与您讨论编译期间发生的问题,甚至在尝试运行您的代码之前。Two terms in a row
这是编译器关于阻止它编译代码的原因的英文摘要。我们稍后会回到它。------>
是编译器的说法,它被你写的东西弄糊涂了,它会在 ------>
之后显示你的一些代码。 .⏏
, Unicode 名称为 EJECT SYMBOL
的字符, 插入到代码的显示中。它插入的点应该有助于解释错误消息。在这种情况下,它指向
.say
之间和 "VERBOSE..."
.编译器认为这是连续的两个术语。什么是术语?
考虑以下代码:
start-time + 42
sum(start-time, 42)
术语有点像 terms in mathematics .两个示例表达式都包含术语 start-time
和 42
.整体表达start-time + 42
也是一个术语。表达式 sum(start-time, 42)
可能被称为 sum()
术语或 sum(...)
学期。条款也有点像nouns or noun phrases in natural language .
start-time
和 42
就像名词,因此是术语。 start-time + 42
和 sum(...)
就像名词短语,每个短语也是一个术语。(顺便说一句,在与这个问题相关的意义上,术语与解析有时称为“术语”的“终端”无关。)
现在,如果您尝试编译本节开头的示例代码,您可能已经猜到会发生什么:
Two terms in a row across lines (missing semicolon or comma?)
第一行 ( start-time + 42
) 是一个术语。 sum(start-time, 42)
是另一个术语。它们之间除了线端之外什么都没有。 Raku 显然不喜欢连续的两个术语,而在它们之间没有不是术语的东西,并且空格和行尾不算数。如何避免“连续两项”错误?
运算符如中缀
+
, 后缀 ()
, 和中缀 ,
我在上面的例子中使用的可以用于操作符位置(之前、之后、中间或周围,术语)来形成表达式。 (并且整个表达式本身就是如上所述的术语。)关键字如
for
或 last
, 用在关键字位置,也不是术语(除非你足够疯狂,将它们重新定义为术语,在这种情况下,你可能会得到你应得的奇怪的编译错误。:))但是,像运算符一样,它们必须放在正确的位置或编译器可能认为它们是术语。如果你写 last
在错误的地方,编译器可能会认为 last
是一个术语。你的代码有问题
编译器考虑
.say
(注意末尾的空格)是一个术语,相当于.say()
.所以它会将你写的内容解释为 .say() "VERBOSE..."
这是连续的两个术语。(我建议你接受事实就是如此,但如果你想深入了解方法调用语法的细节以完全理解为什么
invocant.foo ( arrgh, arrgh, ... ) ;
也是“连续两个术语”,请参阅 my answer covering various syntaxes related to routine calls 。)让我们通过更改
.say
来修复您的代码至 say
(没有 .
):say "VERBOSE \"$_ is the string\"" for $*IN.lines() last when "";
编译器返回另一个“连续两个术语”错误,但现在它指向 $*IN.lines()
和 last
.for
关键字及其迭代参数必须位于语句的开头或语句的结尾。你最终使用了它们。但这意味着
for
之后的内容是一个术语(它的迭代参数)。$*IN.lines()
可以作为一个术语。你甚至可以让它成为表达式的一部分,例如。
for flat $*IN.lines(), $*FOO.lines()
循环遍历输入行和来自其他句柄的行。 ( flat
为 for
创建一个列表,通过展平两个单独的列表来循环,一个来自 $*IN.lines()
,另一个来自 $*FOO.lines()
。)但是你没有建立表达式,你只是立即关注
$*IN.lines()
与 last
.因为没有
last
中缀运算符和 last
必须是语句中的第一个单词才能将其解释为关键字 last
,编译器转而解释 last
作为一个术语——因此它看到“连续两个术语”。您需要
last
是一个语句关键字,它需要在 for
的上下文中环形。但是您已经在 for
的上下文中发表了声明。循环,即 say ...
表达/术语。您需要一些括号或类似的东西来允许您编写多个语句。这是一种方法:{ last when ""; say "VERBOSE \"$_ is the string\""; $i=$i+1 } for $*IN.lines();
现在您的代码有效。最后的调整
我不妨做一些最后的调整:
( last when ''; say qq[VERBOSE "$_ is the string"]; $i++ ) for lines ;
{...}
转过来的至 (...)
.它不是更紧凑,但它表明当 for
时,您可以使用括号而不是大括号。写为语句修饰符(即在语句的末尾而不是在开头)。 {...}
创建一个词法范围,而 (...)
才不是;有时,其中之一正是您所需要的。$*IN.
因为有一个 lines
sub 相当于 $*IN.lines()
.()
之后 lines
因为如果 lines
之后没有参数,则不需要它们(或 $*IN.lines
)并且在语句结束之前。''
而不是 ""
因为我认为如果不需要内插引号,使用非内插引号是一个好习惯。qq[...]
因为这意味着您不必逃避 "
在字符串中。$i++
而不是 $i=$i+1
因为它达到了同样的效果,而且我认为它读起来更好。关于compiler-errors - "Two terms in a row"错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50775130/