在函数中§

请参阅主要文档 上下文中的proto

proto 是一种正式声明multi 候选者之间共性的方法。它充当一个包装器,可以验证参数,但不能修改参数。考虑这个基本示例

proto congratulate(Str $reasonStr $name|{*}
multi congratulate($reason$name{
   say "Hooray for your $reason$name";
}
multi congratulate($reason$nameInt $rank{
   say "Hooray for your $reason$name -- got rank $rank!";
}
 
congratulate('being a cool number''Fred');     # OK 
congratulate('being a cool number''Fred'42); # OK
congratulate('being a cool number'42);         # Proto match error 

proto 坚持所有multi congratulate 子例程都符合两个字符串的基本签名,后面可以跟其他参数。| 是一个未命名的 Capture 参数,允许multi 接受其他参数。前两个调用成功,但第三个调用失败(在编译时),因为42 不匹配 Str

say &congratulate.signature # OUTPUT: «(Str $reason, Str $name, | is raw)␤» 

你可以给proto 一个函数体,并将{*}(注意大括号内没有空格)放在你希望执行分派的地方。当你的例程中有一个“洞”时,这会很有用,它会根据给定的参数给出不同的行为

# attempts to notify someone -- False if unsuccessful 
proto notify(Str $userStr $msg{
   my \hour = DateTime.now.hour;
   if 8 < hour < 22 {
      return {*};
   } else {
      # we can't notify someone when they might be sleeping 
      return False;
   }
}

由于protomulti 候选者的包装器,例程的multi 候选者的签名不一定必须与proto 的签名匹配;multi 候选者的参数可以是proto 的子类型,multi 候选者的返回类型可以与proto 的返回类型完全不同。在给proto 一个函数体时,使用这种不同的类型特别有用

enum DebugType <LOG WARNING ERROR>;
 
#|[ Prints a message to stderr with a color-coded key. ] 
proto debug(DebugType:D $typeStr: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)   { }

{*} 总是分派给它被调用的参数的候选者。参数默认值和类型强制转换将起作用,但不会传递。

proto mistake-proto(Str() $strInt $number = 42{*}
multi mistake-proto($str$number{ say $str.^name }
mistake-proto(742);  # OUTPUT: «Int␤» -- not passed on 
mistake-proto('test'); # fails -- not passed on 

一个使用proto 进行方法的较长的示例展示了如何将公共功能提取到一个 proto 方法中。

class NewClass {
    has $.debug is rw = False;
    has $.value is rw = 'Initial value';
    proto method handle| ) {
        note "before value is 「$.value" if $.debug;
        {*}
        note "after value is 「$.value" if $.debug;
    }
    multi method handle(Str $s{
        $.value = $s;
        say 'in string'
    }
    multi method handle(Positional $s{
        $.value = $s[0];
        say 'in positional'
    }
    multi method handle$a$b ) {
        $.value = "$a is looking askance at $b";
        say 'with more than one value'
    }
}
my NewClass $x .= new;
$x.handle('hello world');
$x.handle(<hello world>);
$x.debug = True;
$x.handle('hello world');
$x.handle(<hello world>);
$x.handle('Claire''John');
# OUTPUT: 
# in string 
# in positional 
# before value is 「hello」 
# in string 
# after value is 「hello world」 
# before value is 「hello world」 
# in positional 
# after value is 「hello」 
# before value is 「hello」 
# with more than one value 
# after value is 「Claire is looking askance at John」