摘要 6

编辑注:本文档已过时,保留在此仅供参考。有关当前设计信息,请参阅摘要 6

本文档总结了第六次启示录,涵盖了子例程和新的类型系统。

子例程和其他代码对象

子例程(关键字:sub)是非继承性的具有参数列表的例程。

方法(关键字:method)是可继承的例程,它们始终与一个相关的对象(称为它们的调用者)相关联,并属于特定的类。

子方法(关键字:submethod)是非继承性的方法,或者伪装成方法的子例程。它们有一个调用者和属于特定的类。

多方法(关键字:multi)是不属于特定类的例程,但有一个或多个调用者。

规则(关键字:rule)是执行模式匹配的(语法)方法。它们相关的块具有特殊的语法(见摘要 5)。

(关键字:macro)是调用执行后立即执行的例程(即在编译时)。宏可以返回另一个源代码字符串或解析树。

标准子例程

命名子例程的一般语法可以是以下任何一种

     my RETTYPE sub NAME ( PARAMS ) TRAITS {...}
    our RETTYPE sub NAME ( PARAMS ) TRAITS {...}
                sub NAME ( PARAMS ) TRAITS {...}

匿名子例程的一般语法是

    sub ( PARAMS ) TRAITS {...}

“特性”是新命名的编译时(is)属性。请参阅特性和属性

Perl5子例程声明

您仍然可以像Perl 5那样声明没有参数列表的子例程

    sub foo {...}

参数仍然通过@_数组传入,但它们是实际参数的常量别名

    sub say { print qq{"@_"\n}; }   # args appear in @_

    sub cap { $_ = uc $_ for @_ }   # Error: elements of @_ are constant

如果您需要修改@_的元素,则使用is rw特性声明它

    sub swap (*@_ is rw) { @_[0,1] = @_[1,0] }

原始块也是Perl 6中的可执行代码结构。

每个块都定义了一个子例程,该子例程可以立即执行或作为Code引用参数传递给其他子例程。

“尖括号子例程”

箭头运算符->几乎是匿名sub关键字的同义词。尖括号子例程的参数列表不需要括号,并且尖括号子例程不能指定特性。

    $sq = -> $val { $val**2 };  # Same as: $sq = sub ($val) { $val**2 };

    for @list -> $elem {        # Same as: for @list, sub ($elem) {
        print "$elem\n";        #              print "$elem\n";
    }                           #          }

存根声明

要预先声明一个子例程而不实际定义它,请使用“存根块”

    sub foo {...};     # Yes, those three dots are part of the actual syntax

旧的Perl 5形式

    sub foo;

在Perl 6中是编译时错误(原因在第六次启示录中解释)。

全局作用域子例程

子例程和变量可以在全局命名空间中声明,此后在程序中的任何地方都是可见的。

全局子例程和变量通常通过在标识符前加*来引用,但如果引用是无歧义的,则可以省略

    $*next_id = 0;
    sub *saith($text)  { print "Yea verily, $text" }

    module A {
        my $next_id = 2;    # hides any global or package $next_id
        saith($next_id);    # print the lexical $next_id;
        saith($*next_id);   # print the global $next_id;
    }

    module B {
        saith($next_id);    # Unambiguously the global $next_id
    }

Lvalue 子例程

Lvalue 子例程返回一个“代理”对象,它可以被赋值。它被称为代理,因为该对象通常代表子例程调用的目的或结果。

使用is rw特性指定子例程为lvalue。

Lvalue 子例程可以返回一个变量

    my $lastval;
    sub lastval () is rw { return $lastval }

or the result of some nested call to an lvalue subroutine:

    sub prevval () is rw { return lastval() }

或具有适当程序化的FETCHSTORE方法的特殊绑定代理对象

    sub checklastval ($passwd) is rw {
        my $proxy is Proxy(
                FETCH => sub ($self) {
                            return lastval();
                         },
                STORE => sub ($self, $val) {
                            die unless check($passwd);
                            lastval() = $val;
                         },
        );
        return $proxy;
    }

操作符重载

运算符只是具有特殊名称的子例程。

一元运算符定义为前缀或后缀

    sub prefix:OPNAME  ($operand) {...}
    sub postfix:OPNAME ($operand) {...}

二元运算符定义为中缀

    sub infix:OPNAME ($leftop, $rightop) {...}

括号运算符定义为中括号。前导和尾随分隔符的组合是运算符的名称。

    sub circumfix:LEFTDELIM...RIGHTDELIM ($contents) {...}
    sub circumfix:DELIMITERS ($contents) {...}

如果左右定界符没有用“...”分开,那么DELIMITERS字符串必须具有偶数个字符。前半部分被视为开定界符,后半部分被视为闭定界符。

运算符名称可以是任何Unicode字符序列。例如

    sub infix:(c)        ($text, $owner) { return $text but Copyright($owner) }
    method prefix:± (Num $x) returns Num { return +$x | -$x }
    multi postfix:!             (Int $n) { $n<2 ?? 1 :: $n*($n-1)! }
    macro circumfix:<!--...-->   ($text) { "" }

    my $document = $text (c) $me;

    my $tolerance = ±7!;

    <!-- This is now a comment -->

参数和参数

Perl 6子例程可以用参数列表声明。

默认情况下,所有参数都是对应参数的常量别名——参数只是原始参数的另一个名称,但无法通过它修改参数。要允许修改,请使用is rw特性。要按拷贝传递,请使用is copy特性。

参数可以是必需的或可选的。它们可以通过位置或名称传递。单个参数可以对其对应参数提供标量或列表上下文。

指定给必需参数的参数必须先于指定给可选参数的参数。指定给位置参数的参数必须先于指定给命名参数的参数。

调用参数

方法调用参数指定为参数列表中的第一个参数,其后直接跟一个冒号(而不是逗号)

    method get_name ($self:) {...}
    method set_name ($me: $newname) {...}

对应的参数(调用者)在标量上下文中评估,并作为方法调用操作符的左操作数传递

    print $obj.get_name();
    $obj.set_name("Sam");

多方法调用参数在参数列表的开头指定,调用参数列表以冒号结束

    multi handle_event ($window, $event: $mode) {...}    # two invocants

多方法调用参数按位置传递,尽管第一个调用参数可以通过方法调用语法传递

    # Multimethod calls...
    handle_event($w, $e, $m);
    $w.handle_event($e, $m);

调用参数还可以使用间接对象语法传递,调用参数后跟一个冒号。冒号只是逗号的特殊形式,具有相同的优先级

    # Indirect method call...
    set_name $obj: "Sam";

    # Indirect multimethod call...
    handle_event $w, $e: $m;

传递过多的或过少的调用参数是一个致命错误。

第一个调用参数始终是相应方法或多方法的主题。

编辑注:本文档已过时,保留在此仅供参考。有关当前设计信息,请参阅摘要 6

必需参数

必需参数在子例程参数列表的开头指定

    sub numcmp ($x, $y) { return $x <=> $y }

对应的参数在标量上下文中评估,可以按位置或按名称传递。要按名称传递参数,将其指定为对:parameter_name => argument_value

    $comparison = numcmp(2,7);
    $comparison = numcmp(x=>2, y=>7);
    $comparison = numcmp(y=>7, x=>2);

传递错误数量的必需参数是一个致命错误。

子例程拥有的必需参数的数量可以通过调用其.arity方法确定

    $args_required = &foo.arity;

可选参数

可选位置参数在所有必需参数之后指定,并且在参数之前用?标记

    sub my_substr ($str, ?$from, ?$len) {...}

等号=引入默认值

    sub my_substr ($str, ?$from = 0, ?$len = Inf) {...}

默认值可以在运行时计算。它们甚至可以使用前面参数的值

    sub xml_tag ($tag, ?$endtag = matching_tag($tag) ) {...}

对应于可选参数的参数在标量上下文中评估。它们可以省略、按位置传递或按名称传递

    my_substr("foobar");            # $from is 0, $len is infinite
    my_substr("foobar",1);          # $from is 1, $len is infinite
    my_substr("foobar",1,3);        # $from is 1, $len is 3
    my_substr("foobar",len=>3);     # $from is 0, $len is 3

缺失的可选参数默认为其默认值,如果没有默认值,则默认为undef

命名参数

命名参数跟在签名中的任何必需或可选参数之后。它们在参数之前用+标记。

    sub formalize($text, +$case, +$justify) {...}

对应于命名参数的参数在标量上下文中评估。它们只能按名称传递,因此传递顺序无关紧要,只要它们跟在所有位置参数之后即可。

    $formal = formalize($title, case=>'upper');
    $formal = formalize($title, justify=>'left');
    $formal = formalize($title, justify=>'right', case=>'title');

命名参数始终是可选的。命名参数的默认值与可选参数的默认值定义方式相同。如果没有默认值,命名参数默认为undef

列表参数

列表参数捕获一系列数据。它们用于需要灵活传递参数数量的子例程中,如print。它们也被称为“变元参数”,因为它们接受一个可变数量的参数。

可变参数跟随任何必需或可选参数。它们在参数前用*标记

    sub duplicate($n, *@data, *%flag) {...}

命名可变参数绑定到可变散列(如上例中的*%flag)。此类参数在标量上下文中进行评估。任何剩余的可变参数(如上例中的*@data)绑定到可变数组,并在列表上下文中进行评估。

例如

    duplicate(3, reverse=>1, collate=>0, 2, 3, 5, 7, 11, 14);

    # The @data parameter receives [2, 3, 5, 7, 11, 14]
    # The %flag parameter receives { reverse=>1, collate=>0 }

可变标量参数捕获可变数组原本的第一个元素

    sub head(*$head, *@tail)         { return $head }
    sub neck(*$head, *$neck, *@tail) { return $neck }
    sub tail(*$head, *@tail)         { return @tail }

    head(1, 2, 3, 4, 5);        # $head parameter receives 1
                                # @tail parameter receives [2, 3, 4, 5]

    neck(1, 2, 3, 4, 5);        # $head parameter receives 1
                                # $neck parameter receives 2
                                # @tail parameter receives [3, 4, 5]

可变标量仍然对其参数施加列表上下文

可变参数是惰性处理的——列表仅在实际上访问单个元素时才展开成数组

        @fromtwo = tail(1..Inf);        # @fromtwo contains a lazy [2..Inf]

展开参数列表

一元前缀运算符*展开其操作数(允许数组元素用作参数列表)。*运算符还将其操作数及其参数列表中的任何后续参数评估为列表上下文。

    sub foo($x, $y, $z) {...}    # expects three scalars
    @onetothree = 1..3;          # array stores three scalars

    foo(1,2,3);                  # okay:  three args found
    foo(@onetothree);            # error: only one arg
    foo(*@onetothree);           # okay:  @onetothree flattened to three args

*运算符是惰性展开的——数组仅在子例程中实际需要展开时才展开。要在将列表传递给子例程之前进行展开,请使用一元前缀**运算符

    foo(**@onetothree);          # array flattened before &foo called

管道运算符

子例程调用的可变数组可以从正常的参数列表中单独传递,通过使用任一“管道”运算符:<====>

每个运算符都期望在其“锐”端找到对可变子例程的调用,并在其“钝”端找到值列表

    grep { $_ % 2 } <== @data;

    @data ==> grep { $_ % 2 };

首先,它展开钝端上的值列表。然后,它将该展开后的列表绑定到锐端子例程的可变参数。因此,上面的两个调用都相当于

    grep { $_ % 2 } *@data;

左向管道是显式表示操作链中数据典型从右到左流动的一种方便方式

    @oddsquares = map { $_**2 } sort grep { $_ % 2 } @nums;

    # more clearly written as...

    @oddsquares = map { $_**2 } <== sort <== grep { $_ % 2 } <== @nums;

右向管道是反转操作链中正常数据流的一种方便方式,使其从左到右读取

    @oddsquares =
            @nums ==> grep { $_ % 2 } ==> sort ==> map { $_**2 };

如果管道锐端的操作数不是对可变操作的调用,则它必须是一个变量。在这种情况下,列表操作数被分配给该变量。这种特殊情况允许进行“纯”处理链

    @oddsquares <== map { $_**2 } <== sort <== grep { $_ % 2 } <== @nums;

    @nums ==> grep { $_ % 2 } ==> sort ==> map { $_**2 } ==> @oddsquares;

闭包参数

使用&符号声明的参数将块、闭包或子例程作为其参数。闭包参数可以是必需的、可选的或命名的。

    sub limited_grep (Int $count, &block, *@list) {...}

    # and later...

    @first_three = limited_grep 3 {$_<10} @data;

在子例程内,闭包参数可以像任何其他词法作用域的子例程一样使用

    sub limited_grep (Int $count, &block, *@list) {
        ...
        if block($nextelem) {...}
        ...
    }

闭包参数可以有自己的签名(其中可以省略参数名称)

    sub limited_Dog_grep ($count, &block(Dog), Dog *@list) {...}

甚至还有返回类型

    sub limited_Dog_grep ($count, &block(Dog) returns Bool, Dog *@list) {...}

当将具有此签名类型的参数传递给闭包参数时,该参数必须是一个具有兼容参数列表和返回类型的Code对象。

解包数组参数

除了将数组参数指定为数组外

    sub quicksort (@data, ?$reverse, ?$inplace) {
        my $pivot := shift @data;
        ...
    }

可以通过指定参数为参数的匿名数组来将其分解成组件

    sub quicksort ([$pivot, *@data], ?$reverse, ?$inplace) {
        ...
    }

此子例程仍然期望一个数组作为其第一个参数,就像第一个版本一样。

编辑注:本文档已过时,保留在此仅供参考。有关当前设计信息,请参阅摘要 6

属性参数

如果方法的参数在符号(如属性)之后声明了点.

    method initialize($.name, $.age) {}

则直接将参数分配给具有相同名称的对象属性。这避免了经常需要编写像这样的代码

    method initialize($name, $age) {
        $.name = $name;
        $.age  = $age;
    }

占位符变量

尽管每个裸块都是一个闭包,但裸块不能有显式的参数列表。相反,它们使用标记有符号后的撇号(^)的“占位符”变量。

在块中使用占位符定义了一个隐式参数列表。签名是不同占位符名称的列表,按Unicode顺序排序。所以

    { $^y < $^z && $^x != 2 }

    sub ($x,$y,$z) { $y < $z && $x != 2 }

类型

这些是Perl 6中的标准类型名称(至少这周是这样的)

    bit         single native bit
    int         native integer
    str         native string
    num         native floating point
    ref         native pointer 
    bool        native boolean
    Bit         Perl single bit (allows traits, aliasing, etc.)
    Int         Perl integer (allows traits, aliasing, etc.)
    Str         Perl string
    Num         Perl number
    Ref         Perl reference
    Bool        Perl boolean
    Array       Perl array
    Hash        Perl hash
    IO          Perl filehandle
    Code        Base class for all executable objects
    Routine     Base class for all nameable executable objects
    Sub         Perl subroutine
    Method      Perl method
    Submethod   Perl subroutine acting like a method
    Macro       Perl compile-time subroutine
    Rule        Perl pattern
    Block       Base class for all unnameable executable objects
    Bare        Basic Perl block
    Parametric  Basic Perl block with placeholder parameters
    Package     Perl 5 compatible namespace
    Module      Perl 6 standard namespace
    Class       Perl 6 standard class namespace
    Object      Perl 6 object
    Grammar     Perl 6 pattern matching namespace
    List        Perl list
    Lazy        Lazily evaluated Perl list
    Eager       Non-lazily evaluated Perl list

值类型

显式类型是可选的。Perl变量有两个相关类型:它们的“值类型”和“变量类型”。

值类型指定可以在变量中存储哪些类型的值。值类型以前缀或使用returnsof关键字给出

    my Dog $spot;
    my $spot returns $dog;
    my $spot of Dog;

    our Animal sub get_pet() {...}
    sub get_pet() returns Animal {...}
    sub get_pet() of Animal {...}

数组或哈希上的值类型指定每个元素存储的类型

    my Dog @pound;  # each element of the array stores a Dog

    my Rat %ship;   # the value of each entry stores a Rat

变量类型

变量类型指定变量本身的实现方式。它作为变量的一个特性给出

    my $spot is Scalar;             # this is the default
    my $spot is PersistentScalar;
    my $spot is DataBase;

定义变量类型是Perl 6中与Perl 5中的绑定变量等效的操作。

分层类型

非标量类型可以是合格的,以便指定其每个元素存储的类型

    my Egg $cup;                       # the value is an Egg
    my Egg @carton;                    # each elem is an Egg
    my Array of Egg @box;              # each elem is an array of Eggs
    my Array of Array of Egg @crate;   # each elem is an array of arrays of Eggs
    my Hash of Array of Recipe %book;  # each value is a hash of arrays of Recipes

每个连续的of都使其右侧的类型成为左侧类型的参数。因此

    my Hash of Array of Recipe %book;

意味着

    my Hash(returns=>Array(returns=>Recipe)) %book;

由于在指定复杂类型时实际变量可能难以找到,因此还有一个后缀形式

    my Hash of Array of Recipe %book;           # HoHoAoRecipe
    my %book of Hash of Array of Recipe;        # same thing
    my %book returns Hash of Array of Recipe;   # same thing

returns形式在子程序中更为常见

    my Hash of Array of Recipe sub get_book () {...}
    my sub get_book () of Hash of Array of Recipe {...}
    my sub get_book returns Hash of Array of Recipe {...}

联合类型

在任何可以使用单个类型的地方,都可以使用类型的联合

    my Int|Str $error = $val;              # can assign if $val~~Int or $val~~Str

    if $shimmer.isa(Wax & Topping) {...}   # $shimmer must inherit from both

参数类型

参数可以指定类型,就像任何其他变量一样

    sub max (int @array is rw) {...}
    sub max (@array of int is rw) {...}

返回类型

在作用域内的子程序上,可以在名称之前或之后指定返回类型

    our Egg sub lay {...}
    our sub lay returns Egg {...}

    my Rabbit sub hat {...}
    my sub hat returns Rabbit {...}

如果子程序没有显式地指定作用域,则它属于当前命名空间(模块、类、语法或包)。任何返回类型都必须在名称之后

    sub lay returns Egg {...}

在匿名子程序上,任何返回类型只能放在名称之后

    $lay = sub returns Egg {...};

除非你使用了“匿名声明符”(a/an

    $lay = an Egg sub {...};
    $hat = a Rabbit sub {...};

属性和特性

编译时属性现在被称为“特性”。is NAME (DATA)语法在声明部分定义了容器和子程序的特性

    my $pi is constant = 3;

    my $key is Persistent(file=>".key");

    sub fib is cached {...}

will NAME BLOCK语法是is NAME (BLOCK)的同义词

    my $fh will undo { close $fh };    # Same as: my $fh is undo({ close $fh });

but NAME (DATA)语法指定了值上的运行时属性

    my $pi = 3 but Approximate("legislated");

    sub system {
        ...
        return $error but false if $error;
        return 0 but true;
    }

子程序特性

以下特性可以声明在子程序的整体上(而不是在单个参数上)。

is signature

子程序的签名——通常通过提供参数列表和/或返回类型隐式声明。

returns/is returns

子程序返回的类型。

will do

当子程序被调用时执行的代码块——通常通过在子程序签名定义之后提供代码块隐式声明。

is rw

将子程序标记为返回一个左值。

is parsed

指定宏调用解析的规则。

is cached

将子程序标记为被缓存。

is inline

建议编译器通过内联优化子程序。

is tighter/is looser/is equiv

指定运算符相对于现有运算符的优先级。

is assoc

指定运算符的结合性。

PRE/POST

标记在子程序的do块之前/之后无条件执行的代码块。这些代码块必须返回一个真值,否则会抛出异常。

FIRST/LAST/NEXT/KEEP/UNDO等。

标记在子程序的do块之前或之后有条件执行的代码块。这些代码块的返回值被忽略。

编辑注:本文档已过时,保留在此仅供参考。有关当前设计信息,请参阅摘要 6

参数特性

以下特性可以应用于许多类型的参数。

is constant

指定参数不能被修改(例如分配、增加)。这是参数的默认值。

is rw

指定参数可以被修改(分配、增加等)。要求相应的参数是一个左值或可以被转换为左值。

当应用于可变参数时,rw特质应用于列表中的每个元素

    sub incr (*@vars is rw) { $_++ for @vars }

是引用

指定参数是通过引用传递的。与is rw不同,相应的参数必须已经是一个合适的左值。不尝试强制转换或自动初始化。

是复制

指定参数接收原始参数的一个独立、可读写副本。这通常称为“按值传递”。

    sub reprint ($text, $count is copy) {
        print $text while $count-->0;
    }

是上下文(TYPE)

指定参数应用于其参数的上下文。通常用于使最终列表参数应用一系列标量上下文

    # &format may have as many arguments as it likes,
    # each of which is evaluated in scalar context

    sub format(*@data is context(Scalar)) {...}

高级子程序功能

&_子程序

&_始终是当前子程序的别名,就像$_是当前主题的别名一样

    my $anonfactorial = sub (Int $n) {
                            return 1 if $n<2;
                            return $n * &_($n-1)
                        };

caller函数

caller函数返回一个对象,描述了一个特定的“更高”的动态作用域,当前作用域是从该作用域调用的。

    print "In ",           caller.sub,
          " called from ", caller.file,
          " line ",        caller.line,
          "\n";

caller可以给出参数,告诉它要查找哪种更高作用域,以及查找时要跳过多少个这样的作用域

    $caller = caller;                      # immediate caller
    $caller = caller Method;               # nearest caller that is method
    $caller = caller Bare;                 # nearest caller that is bare block
    $caller = caller Sub, skip=>2;         # caller three levels up
    $caller = caller Block, label=>'Foo';  # caller whose label is 'Foo'

want函数

want函数返回一个对象,包含有关当前块、闭包或子程序被调用的上下文的信息。

返回的上下文对象通常与智能匹配(~~)或when进行测试

   given want {
        when Scalar {...}           # called in scalar context
        when List   {...}           # called in list context
        when Lvalue {...}           # expected to return an lvalue
        when 2      {...}           # expected to return two values
        ...
    }

或者调用它对应的方法

       if (want.Scalar)    {...}    # called in scalar context
    elsif (want.List)      {...}    # called in list context
    elsif (want.rw)        {...}    # expected to return an lvalue
    elsif (want.count > 2) {...}    # expected to return more than two values

leave函数

return语句会导致最内层的周围子程序、方法、规则、宏或多方法返回。

要从其他类型的代码结构返回,请使用leave函数

    leave;                      # return from innermost block of any kind
    leave Method;               # return from innermost calling method
    leave &_ <== 1,2,3;         # Return from current sub. Same as: return 1,2,3
    leave &foo <== 1,2,3;       # Return from innermost surrounding call to &foo
    leave Loop, label=>'COUNT'; # Same as: last COUNT;

临时化

temp函数临时替换给定作用域中的一个变量、子程序或其他对象

    {
       temp $*foo = 'foo';      # Temporarily replace global $foo
       temp &bar = sub {...};   # Temporarily replace sub &bar
       ...
    } # Old values of $*foo and &bar reinstated at this point

temp调用其参数的.TEMP方法。该方法预期返回一个引用到子程序,稍后可以用来恢复对象的当前值。在temp应用的范围的词法作用域结束时,由.TEMP方法返回的子程序被执行。

变量的默认.TEMP方法只是创建一个闭包,将变量的预temp值赋回变量。

可以通过编写具有自己的.TEMP方法的存储类来创建新的临时化类型

    class LoudArray is Array {
        method TEMP {
            print "Replacing $_.id() at $(caller.location)\n";
            my $restorer = .SUPER::TEMP();
            return { 
                print "Restoring $_.id() at $(caller.location)\n";
                $restorer();
            };
        }
    }

您还可以通过给它们一个TEMP块来修改临时化代码结构的行为。与.TEMP方法一样,这个块预期返回一个闭包,该闭包将在临时化作用域结束时执行,以将子程序恢复到其预temp状态

    my $next = 0;
    sub next {
        my $curr = $next++;
        TEMP {{ $next = $curr }}  # TEMP block returns the closure { $next = $curr }
        return $curr;
    }

包装

每个子程序都有一个.wrap方法。此方法期望一个由一个块、闭包或子程序组成的单一参数。该参数必须包含对特殊call函数的调用

    sub thermo ($t) {...}   # set temperature in Celsius, returns old temp

    # Add a wrapper to convert from Fahrenheit...

    $id = &thermo.wrap( { call( ($^t-32)/1.8 ) } );

.wrap的调用用闭包参数替换原始子程序,并安排闭包对call的调用调用原始(未包装)版本的子程序。换句话说,对.wrap的调用大致相当于

    &old_thermo := &thermo;
    &thermo := sub ($t) { old_thermo( ($t-32)/1.8 ) }

.wrap的调用返回一个唯一标识符,稍后可以将其传递给.unwrap方法,以撤销包装

    &thermo.unwrap($id);

包装也可以通过临时化限制在特定的动态作用域中

    # Add a wrapper to convert from Kelvin
    # wrapper self-unwraps at end of current scope

    temp &thermo.wrap( { call($^t + 273.16) } );

柯里化

每个子程序都有一个.assuming方法。此方法接受一系列命名参数,其名称必须与子程序的参数匹配

    &textfrom := &substr.assuming(str=>$text, len=>Inf);

它返回一个引用到子程序,该子程序实现与原始子程序相同的行为,但已将传递给.assuming的值绑定到相应的参数

    $all  = $textfrom(0);   # same as: $all  = substr($text,0,Inf);
    $some = $textfrom(50);  # same as: $some = substr($text,50,Inf);
    $last = $textfrom(-1);  # same as: $last = substr($text,-1,Inf);

use语句的结果是一个(编译时)对象,该对象还具有一个.assuming方法,允许用户同时绑定所有模块的子程序/方法等参数

    (use IO::Logging).assuming(logfile => ".log");

其他事项

匿名哈希与块

{...} 总是一个块/闭包,除非它只包含一个列表,且该列表的第一个元素是一个哈希或一对。

标准的 pair LIST 函数等价于

    sub pair (*@LIST) {
        my @pairs;
        for @LIST -> $key, $val {
            push @pairs, $key=>$val;
        }
        return @pairs;
    }

标准的 hash 函数接受一个块,在列表上下文中评估它,并从结果键值列表构建一个匿名哈希。

    $ref = hash { 1, 2, 3, 4, 5, 6 };   # Anonymous hash
    $ref = sub  { 1, 2, 3, 4, 5, 6 };   # Anonymous sub returning list
    $ref =      { 1, 2, 3, 4, 5, 6 };   # Anonymous sub returning list
    $ref =      { 1=>2, 3=>4, 5=>6 };   # Anonymous hash
    $ref =      { 1=>2, 3, 4, 5, 6 };   # Anonymous hash

作为左值的一对

一对可以用作左值。一对的值是赋值的接收者

    (key => $var) = "value";

绑定一对时,可以使用名称来“匹配”左值和右值

    (who => $name, why => $reason) := (why => $because, who => "me");

作用域之外的名称

$CALLER::varname 指定了从调用当前块/闭包/子例程的动态作用域中可见的 $varname

$MY::varname 指定了在当前词法作用域中声明的词法 $varname

$OUTER::varname 指定了在当前词法作用域周围声明的词法 $varname(即定义当前块的上下文作用域)。

标签

反馈

这篇文章有什么问题吗?请通过在 GitHub 上打开问题或拉取请求来帮助我们。