错误消息的一般解释
===SORRY!=== Error while compiling ...
当你看到一个SORRY!
,那么您就知道编译器正在与您讨论编译期间发生的问题,甚至在尝试运行您的代码之前。
Two terms in a row
这是编译器关于阻止其编译代码的原因的英文摘要。我们稍后再回来讨论这个问题。
The ------>
是编译器表示它对您所编写的内容感到困惑的方式,并且它将在------>
.
The ⏏
,一个 Unicode 名称为的字符EJECT SYMBOL
,被插入到代码的显示中。它插入的点应该有助于解释错误消息。
在这种情况下,它指向.say
and "VERBOSE..."
。编译器认为这是连续的两个术语。
什么是术语?
考虑以下代码:
start-time + 42
sum(start-time, 42)
条款有点像数学术语 https://en.wikipedia.org/wiki/Term_%28logic%29。两个示例表达式都包含术语start-time
and 42
。整体表达start-time + 42
也是一个术语。表达方式sum(start-time, 42)
可能被称为sum()
术语或sum(...)
term.
条款也有点像自然语言中的名词或名词短语 https://en.wikipedia.org/wiki/Terminology. start-time
and 42
就像名词,因此是术语。start-time + 42
and sum(...)
就像名词短语一样,每个短语也是一个术语。
(顺便说一句,术语,在与这个问题相关的意义上,是not与解析“终端”(有时称为“术语”)相关。)
现在您可能能够猜测如果您尝试编译本节开头的示例代码会发生什么:
Two terms in a row across lines (missing semicolon or comma?)
第一行(start-time + 42
) 是一个术语。sum(start-time, 42)
是另一个术语。除了线端之外,它们之间没有任何东西。 Raku 显然不喜欢连续两个术语之间没有非术语的东西,并且空格和行尾不计算在内。
如何避免“连续两项”错误?
运算符喜欢中缀+
, 后环绕()
, 和中缀,
我在上面的示例中使用的可以在运算符位置(术语之前、之后、之间或周围)使用来形成表达式。 (如上所述,整体表达式本身就是术语。)
关键词如for
or last
,用于关键字位置,也是not术语(除非你疯狂到将它们重新定义为术语,在这种情况下,你可能会得到你应得的奇怪的编译错误。:))但是,像运算符一样,它们必须放置在正确的位置,否则编译器可能会认为它们是条款。如果你写last
在错误的地方,编译器可能会认为last
是一个术语。
你的代码有问题
编译器认为.say
(注意末尾的空格)是一个术语,相当于.say()
。所以它把你写的解释为.say() "VERBOSE..."
这是连续两个术语。
(我建议您接受事实如此,但如果您希望深入研究方法调用语法的细节以完全理解原因invocant.foo ( arrgh, arrgh, ... ) ;
也是“连续两项”,参见我的回答涵盖了与例程调用相关的各种语法 https://stackoverflow.com/a/50283014/1077672.)
让我们通过更改来修复您的代码.say
to say
(没有.
):
say "VERBOSE \"$_ is the string\"" for $*IN.lines() last when "";
编译器返回另一个“连续两项”错误,但现在它指向$*IN.lines()
and last
.
The for
关键字及其迭代参数必须位于语句的开头或结尾。你最后已经使用了它们。
但这意味着之后发生的事情for
是一个项(其迭代参数)。
$*IN.lines()
可以作为一个术语。
您甚至可以将其作为表达式的一部分,例如。for flat $*IN.lines(), $*FOO.lines()
循环输入线和来自其他句柄的线。 (这flat
为以下内容创建一个列表for
通过展平两个单独的列表来循环,其中一个来自$*IN.lines()
,另一个来自$*FOO.lines()
.)
但你没有建立一个表达式,你只是立即跟随$*IN.lines()
with 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 ;
-
我已经从{...}
to (...)
。它并不更紧凑,但它表明当for
被写成语句修饰符(即在语句的末尾而不是在开头)。这{...}
创建一个词法范围,而(...)
才不是;有时,其中之一正是您所需要的。
-
你不需要$*IN.
因为有一个lines
子相当于$*IN.lines()
.
-
我已经放弃了()
after lines
因为如果之后没有参数就不需要它们lines
(or $*IN.lines
) 和语句结束之前。
-
我用过''
代替""
因为我认为如果不需要插值引号,使用非插值引号是一个好习惯。
-
我用过qq[...]
因为这意味着你不必逃避"
在字符串中。
-
我用过$i++
而不是$i=$i+1
因为它达到了同样的效果,而且我认为它读起来更好。