@jjmerelo 的回答涵盖了基础知识。这个补充性的答案旨在有点详尽但希望不会令人筋疲力尽,涵盖了陷阱、罕见情况和建议。
foo: valuea, valueb, ...
也许令人惊讶的是,这不是调用称为foo 的子或方法。
而是以label、foo: 开头的语句。
您问题中的say: 行在普通程序中不起作用:
say: <a b c>; # Useless use of constant value a b c ...
“无用使用”警告意味着 <a b c> 没有以有用的方式使用。 say: 没有对值列表做任何事情。它只是一个不做任何事情的标签。
大概您正在使用类似 Perl 6 REPL 的东西。如果没有使用,REPL 会自动 says 行中的最后一个值,从而使该行看起来可以在没有警告的情况下工作。
.a-method:
如果postfix method call using the form .a-method 除了调用者之外没有参数(. 左侧的参数,如果没有显式调用者,则为 the current topic),那么您可以将其写成以下形式:
42.say ;
您可以选择附加一个冒号:
42.say: ;
没有很好的理由,但它符合:
.a-method: arg2, arg3, ...
如果您想为后缀 .a-method 调用提供一个或多个参数(除了调用者),那么您必须选择两种方法之一来引入它们。
一种方法是在方法名称之后、参数之前立即写一个冒号。方法名和冒号之间不能有空格,并且在方法参数之前的冒号之后必须有空格。1
例如,以下方法调用中Numeric 参数前使用冒号:
say <abc 2 def ghi> .first: Numeric ; # 2
在上述行中,方法调用表达式 (.first: Numeric) 在语句终止符 (;) 处结束。如果有一个封闭的子表达式,例如数组下标,则方法调用表达式在该子表达式的末尾结束:
say .[1 + .first: Numeric] given <abc 2 def ghi> ; # ghi
冒号形式的方法调用的参数列表也由有效的statement modifier 结束,例如given:
say .first: Numeric given <abc 2 def ghi> ; # 2
a-sub arg1, arg2, ...
这是子程序调用的对应形式。唯一的格式差异是子名称前没有调用者或.,您必须省略子名称后的冒号。
.a-method( arg2, arg3, ... )
a-sub( arg1, arg2, ... )
用于方法和子调用的另一种常见形式是在方法或子名称之后立即使用括号来分隔参数。左括号必须紧跟,例程名称和( 之间不能有空格。
下面是.first 方法使用的括号:
say 1 + .first(Numeric) given <abc 2 def ghi> ; # 3
这样的优点是它可以说比使用外部括号更漂亮:
say 1 + (.first: Numeric) given <abc 2 def ghi> ; # 3
如果您想将子调用直接放在双引号字符串中,您需要在子名称前面加上 & sigil 并使用后缀括号形式:
my @array = <abc 2 def ghi> ;
say "first number is &first(Numeric,@array)" ; # first number is 2
要进行方法调用,您必须再次使用后缀括号形式,并且还必须提供显式调用者(不能只写"Some text .a-method()"):
my @array = <abc 2 def ghi> ;
say "first number is @array.first(Numeric)" ; # first number is 2
如果没有参数(除了方法调用的调用者),如果你想在字符串中插入子或方法调用,你仍然需要使用这个带有空括号的表单:
my @array = <abc 2 def ghi> ;
say "no method call @array[3].uc" ; # no method call ghi.uc
say "with method call @array[3].uc()" ; # with method call GHI
say "&rand"; # &rand
say "&rand()"; # 0.929123203371282
.a-method ( arrgh, arrgh, ... ) ;
这行不通。
因为.a-method后面没有冒号,所以方法调用被认为是完整的。
这意味着接下来的事情必须是像;这样的表达式/语句结束符,或者对方法调用的结果进行操作的后缀运算符,或者对结果和一些后续参数进行操作的中缀运算符.
但( arrgh, arrgh, ... ) 不是这些。因此,您会收到“连续两个术语”编译错误。
.a-method:( arrgh, arrgh, ... ) ;
.a-method: ( arrgh, arrgh, ... ) ;
一般来说,不要将: 的使用与在参数周围使用括号作为方法调用的一部分混合使用。这样做没有充分的理由,因为它要么不起作用,要么只是偶然起作用,要么起作用但很可能使读者感到困惑。
如果冒号和左括号之间没有空格,则会产生一个神秘的编译错误:
This type (QAST::WVal) does not support positional operations
留出空间似乎可行——但通常只能靠运气:
say .first: (Numeric) given <abc 2 def ghi> ; # 2
(Numeric) 是括号中的单个值,产生Numeric,因此该行与以下内容相同:
say .first: Numeric given <abc 2 def ghi> ; # 2
但是如果括号中有两个或多个参数,事情就会出错。使用以下形式之一:
say .first: Numeric, :k given <abc 2 def ghi> ; # 1
say .first(Numeric, :k) given <abc 2 def ghi> ; # 1
正确生成2 元素的数组索引(“key”),而不是:
say .first: (Numeric, :k) given <abc 2 def ghi> ; # Nil
产生Nil,因为.first 方法对单个 参数没有任何用处,该参数是(Numeric, :k) 形式的列表。
当然,您可能偶尔想要传递一个参数,该参数是括号中的值列表。但是您可以在不使用冒号的情况下这样做。为清楚起见,我建议您改为:
invocant.a-method(( valuea, valueb, ... ));
a-sub ( arrgh1, arrgh2, ... ) ;
正如刚才对方法调用所解释的那样,这会将一个参数传递给a-sub,即单个列表( arrgh1, arrgh2, ... ),这很少是作者的意思。
同样,我的建议是改为:
`a-sub( valuea, valueb, ... ) ;`
或:
`a-sub valuea, valueb, ... ;`
如果您打算传递多个参数,或者如果您希望将列表作为单个参数传递,那么:
`a-sub(( valuea, valueb, ... )) ;`
.a-method : arrgha, arrghb, ...
a-sub : arrgha, arrghb, ...
对于方法表单,这会给您带来“困惑”的编译错误。
如果a-sub 不带参数,则子表单也是如此。如果a-sub 接受参数,您将收到“前面的上下文需要一个术语,但找到了中缀:而不是”编译错误。
.&a-sub
有一个调用表单可以让你调用一个声明为 sub 的例程——但使用.method 调用语法。以下将点左侧的“invocant”qux 作为第一个参数提供给名为a-sub 的子程序:
qux.&a-sub
像往常一样使用: 或括号将其他 参数传递给a-sub:
sub a-sub ($a, $b) { $a == $b }
say 42.&a-sub(42), 42.&a-sub(43); # TrueFalse
say 42.&a-sub: 42; # True
(在本节的原始版本中,我写道不能传递额外的参数。我已经对此进行了测试,并认为不能。但我一定是被某些东西弄糊涂了。@Enheh 的评论让我重新测试并发现可以像普通方法调用一样传递额外的参数。谢谢@Enheh。:))
a-method( invocant: arg2, arg3, ... )
a-method invocant: arg2, arg3, ...
在设计文档中称为“间接对象表示法”,这些格式是一种未记录且很少见的方法调用形式,其中调用模仿方法声明——方法名称先出现,然后调用者后跟冒号:
say first <abc 2 def ghi>: Numeric ; # 2
注意say 是一个sub 调用,因为下一个标记first 后面没有冒号。相比之下,first 是一个 方法 调用,因为它后面的标记 后跟一个冒号。
脚注
1此答案中有关空格/间距的所有 cmets 忽略 unspacing。