class Routine is Block { }

Routine 是一个代码对象,适用于大于 Block 的代码单元。Routine 是 Sub(以及运算符)和 Method 的公共超类,这两个主要代码对象用于代码重用,以及 MacroSubmethod

Routine 充当 return 的作用域限制器(即 return 从最内层外部 Routine 返回)。

Routine 级别也是处理 多重性(多重子例程和多重方法)的级别。子例程还可以声明为 anon。有关更多信息,请参阅 anon 声明符的文档

Routine 是 Code 层次结构中最低级的对象,它可以通过自动定义且包含相应 Routine 对象的 &?ROUTINE 变量 进行自省。

class Foo {
    submethod bar { &?ROUTINE.^name }
};
say Foo.bar# OUTPUT: «Submethod␤» 

方法§

方法名称§

method name(Routine:D: --> Str:D)

返回子例程或方法的名称。

方法包§

method package(Routine:D:)

返回定义例程的包。

方法多重§

method multi(Routine:D: --> Bool:D)

如果例程是多重子例程或方法,则返回 True。请注意,多重子例程的名称引用其 proto,如果对其调用此方法,则此方法将返回 false。需要在候选本身上调用它

multi foo ($, $) {};
say &foo.multi;             # OUTPUT: «False␤» 
say &foo.candidates».multi# OUTPUT: «(True)␤»

方法候选§

method candidates(Routine:D: --> Positional:D)

返回多重候选列表,或者如果它不是多重候选,则返回一个包含它自己的单元素列表

方法 cando§

method cando(Capture $c)

返回一个候选列表,该列表可以与给定的 Capture 一起调用,按最窄的候选优先的顺序排列。对于方法,Capture 的第一个元素需要是调用者

.signature.say for "foo".^can("comb")[0].cando: \(Cool"o");
# OUTPUT: «(Cool $: Str $matcher, $limit = Inf, *%_)␤»

方法 wrap§

method wrap(Routine:D: &wrapper)

包装(即就地修改)例程。这意味着对该例程的调用首先调用 &wrapper,然后 &wrapper 可以(但不一定)使用 callsamecallwithnextsamenextwith 调度程序调用原始例程。例程的返回值也是包装器的返回值。

wrap 返回一个名为 Routine::WrapHandle 的私有类的实例,您可以将其传递给 unwrap 以还原原始例程。

方法 unwrap§

method unwrap($wraphandle)

在用 wrap 包装后还原原始例程。虽然签名允许传递任何类型,但只有 wrap 返回的 Routine::WrapHandle 类型才能有效使用。

方法 is-wrapped§

method is-wrapped()

返回 TrueFalse,具体取决于 Routine 是否被包装。

方法 yada§

method yada(Routine:D: --> Bool:D)

如果例程是存根,则返回 True

say (sub f() { ... }).yada;      # OUTPUT: «True␤» 
say (sub g() { 1;  }).yada;      # OUTPUT: «False␤»

特性 is cached§

multi trait_mod:<is>(Routine $r:$cached!)

导致例程的返回值被存储,以便在使用相同参数列表进行后续调用时,可以立即返回存储的值,而不是重新运行例程。[1]

当存储和返回计算值比每次重新计算它快得多时,并且节省的时间超过使用更多内存的成本时,这很有用。

即使传递给例程的参数是“引用类型”(例如对象或数组),那么出于缓存的目的,它们也只会根据其内容进行比较。因此,在这种情况下,第二次调用将命中缓存

say foo( [123] );   # runs foo 
say foo( [123] );   # doesn't run foo, uses cached value 

由于它仍处于实验阶段,因此您必须在使用它的任何模块或脚本中插入 use experimental :cached; 语句。

use experimental :cached;
 
sub nth-prime(Int:D $x where * > 0is cached {
    say "Calculating {$x}th prime";
    return (2..*).grep(*.is-prime)[$x - 1];
}
 
say nth-prime(43);
say nth-prime(43);
say nth-prime(43);

生成此输出

Calculating 43th prime
191
191
191

注意:此功能不是线程安全的。

特性 is pure§

multi trait_mod:<is>(Routine $r:$pure!)

将子例程标记为,即断言对于相同的输入,它将始终产生相同输出,而没有任何其他副作用。

is pure 特性是程序员对编译器的承诺,即当在编译时知道参数时,它可以对这些函数的调用进行常量折叠。

sub syllables() is pure {
    say "Generating syllables";
    my @vowels = <a e i o u>;
    return  @vowels.append: <k m n sh d r t y> X~ @vowels;
}

即使函数在特殊情况下引发异常或修改临时对象,您也可以将函数标记为纯函数;因此,is pure 特性可以涵盖编译器无法自行推断的情况。另一方面,您可能不想对生成较大返回值的函数(例如字符串或列表重复运算符、中缀 xxx)进行常量折叠,即使它们是纯函数,以避免生成较大的预编译文件。

要使用特定编译器查看它的操作,您可以尝试此示例

BEGIN { say Begin }
say Start;
say (^100).map: { syllables().pick(4).join(""};
 
 
# Example output: 
# Begin 
# Generating syllables 
# Start 
# (matiroi yeterani shoriyuru... 

从本质上讲,这允许编译器在编译时执行一些操作。常量折叠的好处可能包括更好的性能,尤其是在折叠代码已预编译的情况下。

此外,在汇入上下文中使用纯函数或运算符(即,结果被丢弃)可能会导致警告。代码

sub double($xis pure { 2 * $x };
double(21);
say "anything";
# WARNING: «Useless use of "double(21)" in expression "double(21)" in sink context (line 2)»

如果您想将此特性应用于 multi,则需要将其应用于 proto;否则它将不起作用,至少在 2018.08 及更低版本中。

特性是 rw§

multi trait_mod:<is>(Routine $r:$rw!)

当一个例程使用此特性进行修改时,其返回值将可写。这在返回变量或哈希或数组的可写元素时很有用,例如

sub walk(\thing*@keysis rw {
    my $current := thing;
    for @keys -> $k {
        if $k ~~ Int {
            $current := $current[$k];
        }
        else {
            $current := $current{$k};
        }
    }
    $current;
}
 
my %hash;
walk(%hash'some''key'12= 'autovivified';
 
say %hash.raku;

产生

("some" => {"key" => [Any, [AnyAny"autovivified"]]}).hash

请注意,return 将返回值标记为只读;如果您需要从is rw例程中提前退出,则必须使用 return-rw

特性是 export§

multi trait_mod:<is>(Routine $r:$export!)

将例程标记为导出到世界其他地方

module Foo {
    sub double($xis export {
        2 * $x
    }
}
 
import Foo;         # makes sub double available 
say double 21;      # 42 

在另一个文件内部,您会说 use Foo; 来加载模块并导入导出的函数。

有关更多详细信息,请参见 导出和选择性导入模块

特性是 DEPRECATED§

multi trait_mod:<is>(Routine:D $r:$DEPRECATED!)

Routine标记为已弃用;也就是说,它不应该再继续使用,并最终将被移除。可以指定一个可选消息来指定替换功能

通过同时提供原始(已弃用)和新的Routine,您可以避免在单个版本中发生重大更改,方法是允许用户有时间和说明来更新其代码。仅在至少包含警告和新Routine的一个版本后才删除已弃用的版本。

此代码

sub f() is DEPRECATED('the literal 42'{ 42 }
say f();

生成此输出

42
Saw 1 occurrence of deprecated code.
================================================================================
Sub f (from GLOBAL) seen at:
  deprecated.raku, line 2
Please use the literal 42 instead.
--------------------------------------------------------------------------------
Please contact the author to have these occurrences of deprecated code
adapted, so that this message will disappear!

特性是 hidden-from-backtrace§

multi trait_mod:<is>(Routine:D:$hidden-from-backtrace!)

隐藏例程,使其不显示在默认回溯中。例如

sub inner { die "OH NOEZ" };
sub outer { inner() };
outer();

产生错误消息和回溯

OH NOEZ
  in sub inner at bt.raku:1
  in sub outer at bt.raku:2
  in block <unit> at bt.raku:3

但如果inner标记为hidden-from-backtrace

sub inner is hidden-from-backtrace { die "OH NOEZ" };
sub outer { inner() };
outer();

错误回溯不会显示它

OH NOEZ
  in sub outer at bt.raku:2
  in block <unit> at bt.raku:3

特性是 default§

multi trait_mod:<is>(Routine:D $r:$default!)

有一个针对Routine的特殊特性,称为is default。此特性旨在作为消除歧义multi调用的方式,而这些调用通常会引发错误,因为编译器不知道使用哪一个。这意味着,给定以下两个Routine,将调用具有is default特性的那个。

multi f() is default { say "Hello there" }
multi f() { say "Hello friend" }
f();   # OUTPUT: «"Hello there"␤»

is default特性对于调试和其他用途非常有用,但请记住,它只会解决两个具有相同优先级的Routine之间的歧义分派。如果其中一个Routine比另一个窄,则将调用该Routine。例如

multi f() is default { say "Hello there" }
multi f(:$greet{ say "Hello " ~ $greet }
f();   # "Use of uninitialized value $greet..." 

在此示例中,调用了没有is defaultmulti,因为它实际上比带有它的 Sub 更窄。

特性是 raw§

multi trait_mod:<is>(Routine:D $r:$raw!)

完全访问例程返回的数据结构。

my @zipi = <zape zapatilla>;
sub þor() is raw {
    return @zipi
};
þor()[1= 'pantuflo';
say @zipi;  # OUTPUT: «[zape pantuflo]␤» 

trait 是 test-assertion§

multi trait_mod:<is>(Routine:D:$test-assertion!)

声明一个例程生成测试输出(又名 TAP)。当报告失败时,将使用调用例程的位置,而不是此例程。例如

use Test;
sub foo-test($valueis test-assertion {
    is $value42"is the value 42?";
}
foo-test(666);    # <-- error is reported on this line 

类型图§

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

展开上面的图表

1 [↑] 此功能仍处于实验阶段。请查看实验功能文档中的相应部分