You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于Raku函数签名中双分号的用法及相关疑问

Raku多派发中双分号(;;)的用法解析

先看官方文档里的这段示例代码:

enum DebugType <LOG WARNING ERROR>;
 
#|[ Prints a message to stderr with a color-coded key. ] 
proto debug(DebugType:D $type, Str:D $message --> Bool:_) {
    note sprintf qb/\e[1;%dm[%s]\e[0m %s/, {*}, $type.key, $message
}
multi debug(LOG;; Str:D --> 32)     { }
multi debug(WARNING;; Str:D --> 33) { }
multi debug(ERROR;; Str:D --> 31)   { }

文档中“Long names”小节给出了双分号的说明:

To exclude certain parameters from being considered in multiple dispatch, separate them with a double semicolon.

附带的示例代码:

multi sub f(Int $i, Str $s;; :$b) { say "$i, $s, {$b.raku}" };
f(10, 'answer');
# OUTPUT: «10, answer, Any␤»

针对以上内容,有以下三个疑问及对应的解析:


  • 疑问1:multi debug里为啥要把第一个参数排除在多派发考量外?排除后怎么确定派发哪个子例程?
    首先要纠正一个误解:被排除的不是第一个参数,而是双分号后面的Str:D参数。第一个参数LOG/WARNING/ERROR是枚举字面量,本身就是多派发的核心匹配依据。

    这段代码的逻辑是:proto定义的签名要求第一个参数是DebugType类型实例,第二个是字符串。每个multi子例程已经用具体的枚举值作为第一个参数的匹配条件——这已经足够让Raku的多派发机制确定调用哪个multi。

    把Str:D放在双分号后面,是明确告诉Raku:这个参数不参与多派发的匹配判断。因为三个multi子例程的第二个参数都是Str:D,本来就不会影响派发选择,排除它只是避免编译器做不必要的检查,同时让代码意图更清晰。

    Raku确定派发的逻辑还是看第一个参数的具体枚举值:调用debug(LOG, "xxx")时匹配第一个multi;调用debug(ERROR, "yyy")时匹配第三个,和双分号无关——双分号只是把第二个参数从派发判断里移除了而已。


  • 疑问2:把双分号换成单逗号,输出没差异?
    因为所有multi子例程的第二个参数都是Str:D,不管用逗号还是双分号,Raku的多派发机制在匹配时,这个参数的类型完全一致,不会影响最终选择哪个multi。

    用逗号的话,第二个参数会被纳入派发判断,但由于三个子例程的该参数类型无差异,判断结果和排除它时完全一样,最终调用的都是对应枚举值的multi,输出自然没区别。

    但如果后续修改某个multi的第二个参数类型(比如改成Int:D),差异就会显现:用逗号的话,Raku会同时根据第一个枚举值和第二个参数类型来派发;用双分号的话,第二个参数类型不影响派发,只要第一个参数匹配就会调用,此时若传入字符串就会触发参数类型不匹配的错误。


  • 疑问3:只有一个multi sub f时,双分号怎么影响派发?“Long names”副标题为啥突兀?
    1. 双分号的影响:
      哪怕只有一个multi子例程,双分号的作用依然是排除参数参与多派发。如果后续新增另一个multi sub f,就能看出区别:
      比如新增:

      multi sub f(Int $i, Str $s;; :$b, :$c) { say "$i, $s, {$b.raku}, {$c.raku}" }
      

      此时调用f(10, 'answer', :b(True)),Raku不会因为:$b这个命名参数的存在而选择第二个multi——因为双分号把命名参数排除在了派发判断之外,两个multi的派发判断只看前面的Int $i, Str $s,会因重复匹配报错。
      如果把双分号换成逗号,第二个multi的签名是Int $i, Str $s, :$b, :$c,调用f(10, 'answer', :b(True))时会匹配第一个multi;调用f(10, 'answer', :b(True), :c(False))时会匹配第二个。

    2. “Long names”副标题突兀的原因:
      这明显是文档排版的错误,双分号的功能和“Long names”(长参数名)没有直接关联,大概率是文档编辑时的归类失误,把双分号的说明放错了小节。


内容的提问来源于stack exchange,提问作者AlvaPan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 23:17:17