class Sub is Routine { }

子例程和运算符的类型。使用 sub 声明关键字后跟一个可选的 标识符 来创建子例程。此 简短教程解释了如何声明运算符。有关子例程参数列表的详细信息,请参阅 Signature

请注意,与 强制转换 同名的子例程不会优先于它们。使用 & 符号来调用它们。

sub Int(Str $s){'what?'};
say [IntInt('42'),&Int('42')];
# OUTPUT: «[(Int) 42 what?]␤»

子例程可以使用 myour 进行嵌套和限定,其中 my 是默认值。使用 my 声明的子例程无法从任何外部作用域访问。our 限定的子例程不会重新定义外部作用域中同名的子例程。可以通过闭包从任何外部作用域访问任何子例程。例如,在此示例中

sub can-be-seener$whatever ) {
  my sub can-be-seen ( $objection ) {
    return $whatever but $objection;
  }
  return &can-be-seen
}
 
my $objectioner = can-be-seener"Really?");
say $objectioner(42).Int# OUTPUT: «42␤»

$objectioner 将包含 can-be-seen 子例程,即使它已在另一个作用域中声明;使用 42 调用它将返回 "Really?",其中包含数字 42,如最后一句所示。

运算符§

运算符也是 Sub。它们的定义包括 它们所属的类别 及其 代码、优先级和结合性。它们定义中使用的语法是 扩展标识符 的示例。

特性 §

Trait 是一个子例程,在编译时应用于各种对象,如类、例程或 容器。它使用 trait_mod 声明符声明,后跟一个冒号和一个包含特性名称的字符串文字。单个位置参数定义应用特性的对象类型。单个命名参数定义辅助名称,并在调用特性时可能携带参数。特性是一个特殊的语法类别,允许放在大多数语言对象名称或参数列表之后。

say 'start';
multi trait_mod:<is>(Sub $s:$foo){
    say "⟨is foo⟩ has been called with ⟨$foo⟩ on {$s.WHICH}";
}
sub bar() is foo<oi‽> {
    say 'bar has been called'
}
bar();
# OUTPUT: «⟨is foo⟩ has been called with ⟨oi‽⟩ on Sub|47563000␤start␤bar has been called␤»

使用 解构 来使用复杂参数调用特性。

multi trait_mod:<is>(Variable $a:@foo [$firstpos*@restpos:$named*%restnameds]) {
    say [$firstpos@restpos$named%restnameds]
}
my $x is foo[1,2,3,:named<a>:2b, :3c] = 1
# OUTPUT: «[1 [2 3] a {b => 2, c => 3}]␤»

尽管其语法很奇怪,但特性只是一个普通的 Sub。我们可以对其(甚至其自身)应用特性,并且可以在运行时将特性应用于对象。

multi trait_mod:<is> (Sub $s:$foois foo {
    say 'is foo called'
}
sub bar {}
&trait_mod:<is>(&bar:foo);
# OUTPUT: «is foo called␤is foo called␤»

类型图§

Sub 的类型关系
raku-type-graph Sub Sub Routine Routine Sub->Routine Mu Mu Any Any Any->Mu Callable Callable Code Code Code->Any Code->Callable Block Block Block->Code Routine->Block

展开上面的图表