Wait the light to fall

Raku 中的捕获

焉知非鱼

Capture in Raku

Capture 的定义:

class Capture does Positional does Associative { }

Capture 是一个用于给 code 对象传递参数的容器。Captures 是签名的另一面 — Captures 在调用方定义实参, 而签名(Signatures) 在被调用方定义形式参数。

当你调用 print $a, $b 时, $a, $b 这部分就是一个 Capture。$a, $b 在这儿是实参。

Captures 包含一个 list-like 部分的位置参数和一个 hash-like 部分的具名参数。对于具名参数, Captures 使用一种略微不同的语法而不是普通的 List。有两种简单的方法生成一个具名参数:

  • 使用一个未引起的键命名一个形参, 后面跟着 =>, 然后跟着参数
  • 使用以形参命名的冒号对儿字面量
say unique 1, -2, 2, 3, as => { abs $_ }; # 1, -2, 3
# ... is the same thing as:
say unique 1, -2, 2, 3, :as({ abs $_ });  # 1, -2, 3
# Be careful not to quote the name of a named parameter:
say unique 1, -2, 2, 3, 'as' => { abs $_ }; # 1, -2, 2, 3, "as" => { ... }

单个独立的 Capture 也能被生成, 存储, 然后供之后使用。 在项(term)那儿前置一个反斜线 \ 能生成一个字面的 Capture。通常, 这个 term 会是一个 terms 的列表, 在这个列表里面, 任何 Pair 字面值会被放在 Capture 的具名部分, 而其它 terms 会被放在Capture 的位置(positional) 部分。

my $c = \(42);          # 带有一个 positional 部分的 Capture        
$c = \(1, 2, a => 'b'); # 带有两个 positional 部分和一个具名部分的 Capture

要使用这样的 Capture, 在函数调用里你可以在这个 Capture 前面使用 | , 那么它看起来会像这个 Capture 中的所有值都被作为实参直接传递这个函数了 — 具名参数作为具名参数传递, 而位置参数会作为位置参数传递。 只要你愿意, 你可以重用这个 Capture 任意次, 甚至使用不同的函数。

my $c = \(4,2,3);
reverse(|$c).say; # 3 2 4
sort(5,|$c).say;  # 2 3 4 5

在签名( Signature) 里面, 可以在不含符号的形参那儿前置一个竖线 | 来创建一个 Capture。这会把余下的参数列表打包到那个形参中:

sub f($a, |c) {
    say c;
}

f(1, 2, 3, a => 4, b => 5);
# c  is  \(2, 3, a => 4, b => 5)

请注意,Capture 仍然是列表,因为它们可能包含容器,而不只是值:

my $b = 1;
my $c = \(4,2,$b,3);
sort(|$c).say;        # 1 2 3 4
$b = 6;
sort(|$c).say;        # 2 3 4 6

Capture 方法(From Mu) #

定义为:

method Capture(Mu:D: --> Capture:D)

返回与调用者的公共属性相对应的命名参数的 Capture

class Foo {
    has $.foo = 42;
    has $.bar = 70;
    method bar { 'something else' }
}.new.Capture.say;

# OUTPUT: «\(:bar("something else"), :foo(42))␤» 

Cpature 方法(from List) #

定义为:

method Capture(--> Capture:D)

返回一个 Capture,其中列表中的每个 Pair(如果有)已转换为命名参数(使用Pair string的键)。列表中的所有其他元素按照它们被发现的顺序转换为位置参数,即列表中的第一个非 Pair item 成为第一个位置参数,其获得索引 0,第二个非 pair item 成为第二个位置参数,索引为 1 等。

my $list = (7, 5, a => 2, b => 17);
my $capture = $list.Capture;
say $capture.keys; # OUTPUT: «(0 1 a b)␤» 
my-sub(|$capture); # RESULT: «7, 5, 2, 17» 
 
sub my-sub($first, $second, :$a, :$b) {
    say "$first, $second, $a, $b"
}

一个更高级的例子是所返回的 Capture签名 进行智能匹配。

my $list = (7, 5, a => 2, b => 17);
say so $list.Capture ~~ :($ where * == 7,$,:$a,:$b); # OUTPUT: «True␤» 
 
$list = (8, 5, a => 2, b => 17);
say so $list.Capture ~~ :($ where * == 7,$,:$a,:$b); # OUTPUT: «False␤»