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»