在函数中§

请参阅主要文档 上下文中的多重分派

Raku 允许编写具有相同名称但不同签名的多个例程。当按名称调用例程时,运行时环境将确定合适的候选者并调用它。

每个候选者都用 multi 关键字声明。分派根据参数 arity(数量)、类型和名称发生;在某些情况下,multi 声明的顺序也会发生。考虑以下示例

# version 1 
multi happy-birthday$name ) {
    say "Happy Birthday $name !";
}
 
# version 2 
multi happy-birthday$name$age ) {
    say "Happy {$age}th Birthday $name !";
}
 
# version 3 
multi happy-birthday:$name:$age:$title  = 'Mr' ) {
    say "Happy {$age}th Birthday $title $name !";
}
 
 
# calls version 1 (arity) 
happy-birthday 'Larry';                        # OUTPUT: «Happy Birthday Larry !␤» 
# calls version 2 (arity) 
happy-birthday 'Luca'40;                     # OUTPUT: «Happy 40th Birthday Luca !␤» 
# calls version 3 
# (named arguments win against arity) 
happy-birthdayage => '50'name => 'John' ); # OUTPUT: «Happy 50th Birthday Mr John !␤» 
# calls version 2 (arity) 
happy-birthday'Jack'25 );                  # OUTPUT: «Happy 25th Birthday Jack !␤» 

happy-birthday 子例程的前两个版本仅在 arity(参数数量)上有所不同,而第三个版本使用命名参数,并且仅在使用命名参数时选择它,即使 arity 与另一个 multi 候选者相同。

当两个子例程具有相同的 arity 时,参数的类型会驱动分派;当有命名参数时,即使它们的类型与另一个候选者相同,它们也会驱动分派

multi happy-birthdayStr $nameInt $age ) {
    say "Happy {$age}th Birthday $name !";
}
 
multi happy-birthdayStr $nameStr $title ) {
    say "Happy Birthday $title $name !";
}
 
multi happy-birthdayStr :$nameInt :$age ) {
    say "Happy Birthday $name, you turned $age !";
}
 
happy-birthday 'Luca'40;                 # OUTPUT: «Happy 40th Birthday Luca !␤» 
happy-birthday 'Luca''Mr';               # OUTPUT: «Happy Birthday Mr Luca !␤» 
happy-birthday age => 40name => 'Luca';  # OUTPUT: «Happy Birthday Luca, you turned 40 !␤» 

即使在调用中未提供命名参数,它们也会参与分派。因此,具有命名参数的多候选者将具有优先权。

有关类型约束的更多信息,请参阅 签名 文字的文档。

multi as-json(Bool $d{ $d ?? 'true' !! 'false'}
multi as-json(Real $d{ ~$d }
multi as-json(@d)      { sprintf '[%s]'@d.map(&as-json).join(''}
 
say as-jsonTrue );                        # OUTPUT: «true␤» 
say as-json10.3 );                        # OUTPUT: «10.3␤» 
say as-json( [ True10.3False24 ] );   # OUTPUT: «[true, 10.3, false, 24]␤»

对于某些签名差异(尤其是在使用 where 子句或子集时),将使用多方法或子例程的定义顺序,依次评估每个可能性。有关示例,请参见下面的 按定义顺序进行多重解析

没有特定例程类型的 multi 始终默认为 sub,但您也可以在方法上使用它。候选者是该对象的所有多方法

class Congrats {
    multi method congratulate($reason$name{
        say "Hooray for your $reason$name";
    }
}
 
role BirthdayCongrats {
    multi method congratulate('birthday'$name{
        say "Happy birthday, $name";
    }
    multi method congratulate('birthday'$name$age{
        say "Happy {$age}th birthday, $name";
    }
}
 
my $congrats = Congrats.new does BirthdayCongrats;
 
$congrats.congratulate('promotion','Cindy'); # OUTPUT: «Hooray for your promotion, Cindy␤» 
$congrats.congratulate('birthday','Bob');    # OUTPUT: «Happy birthday, Bob␤»

sub 不同,如果您对多方法使用命名参数,则参数必须是必需参数才能按预期工作。

请注意,非多子例程或运算符将隐藏任何父作用域或子作用域中具有相同名称的多候选者。对于导入的非多候选者也是如此。

多重分派也可以作用于参数特征,具有 is rw 参数的例程比没有这些参数的例程具有更高的优先级

proto þoo (|) {*}
multi þoo$ðar is rw ) { $ðar = 42 }
multi þoo$ðar ) { $ðar + 42 }
my $bar = 7;
say þoo($bar); # OUTPUT: «42␤»