错误信息的一般解释
===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 子,相当于$*IN.lines()。
-
我在lines 之后删除了(),因为如果在lines(或$*IN.lines)之后和语句结束之前没有参数,则不需要它们。
-
我使用了'' 而不是"",因为我认为如果您不需要插值引号,使用非插值引号是一个好习惯。
-
我使用了qq[...],因为这意味着您不必转义字符串中的"。
-
我使用了$i++ 而不是$i=$i+1,因为它达到了相同的效果,而且我认为它读起来更好。