如何使用 `|c` 捕获默认参数?
How do I capture default arguments with `|c`?
我这里有这个功能:
my @modifiers = <command option>;
sub triple(|c(Str:D $app1!, Str:D $app2!, Str:D $key! where .chars == 1, Str:D $mod where ($mod ~~ any @modifiers) = 'command' )) {
print_template(|c);
}
sub print_template(*@values) {
...work done here...
}
我遇到的问题是,如果我在没有第 4 个参数的情况下调用它,例如 triple 'App1', 'App2', 'p';
,默认的 $mod
参数不会传递给 print_template
参数。
有办法做到这一点吗?
对于完整的上下文,这是这里的玩具程序:https://paste.debian.net/1226675/
好的,根据 IRC 中的回复,这似乎不可能。一种建议的解决方法:
sub triple(|c(Str:D $app1!,
Str:D $app2!,
Str:D $key! where .chars == 1,
Str:D $mod where ($mod ~~ any @modifiers) = 'command' )) {
my \d = \(|c[0..2], c[3] // 'command');
print_template(|d);
}
TL;DR 1.问题的解释。 2. DRY 解决方案。 3. DRYest 解决方案:parameters-capture
函数。
问题的解释
呼叫分两步进行:
构造一个呼叫,不知道哪个routine会听到这个呼叫。这包括构造调用参数的捕获。在第 2 步之前,此捕获已经完成并已除尘,不可变。
看看有哪些常规候选人可能会绑定电话。尝试将捕获绑定到他们的签名。例程签名中的某些参数可能会指定默认值,以防缺少参数。
因此,给定一个捕获 c
,您不能更改它来弥补其中不存在的任何参数,并且 Raku 不会自动创建一个新的捕获来伪装任何参数不在里面现在在里面。相反,您将不得不手动添加缺失值。
一个DRY解决方案
字符串 'command'
在您回答的建议解决方案中出现了两次。
编写 DRY 解决方案的一种方法是使用整个捕获,其中将包括所有传递的参数,然后 append 任何 parameters,其中相应的 参数 未 通过。也就是说,而不是:
my \d = \(|c[0..2], c[3] // 'command');
这样写:
my \d = \(|c, |($mod if not c[3]));
DRYest 解决方案:parameters-capture
函数
最终,您的场景需要的是一个完全忽略用于调用例程的 参数 的函数,而只是创建一个新的捕获,其中包含例程的所有 参数。然后一个人可以写,说:
print_template(|parameters-capture);
我觉得这很重要。这意味着遍历例程的参数数据。这大概会通过类似 &?ROUTINE.signature.params
的方式进行。但是 &?ROUTINE
是一个编译时变量,并且是相对于当前例程的,所以你如何在你从 例程中 调用的函数中得到它,你的参数是有兴趣吗?即使你能得到它,你如何从编译时参数数据结构到最终绑定到参数的 运行 时间值?这完全超过了我的工资等级。进行这种胆量编码可能比在 Perl 世界中要容易得多,在 Perl 世界中它意味着 C 编码,但仍然如此。
获得相同总体结果的另一种方法(可能是我要采用的方法)是将其拆分为 multi
并根据参数数量进行分派。这是一种可能的方式(将共享参数的验证移至 proto
:
my @modifiers = <command option>;
proto triple(Str:D, Str:D, Str:D $ where .chars == 1, $?) {*}
multi triple(|c($, $, $, Str:D $ where any @modifiers)) { print_template |c }
multi triple(|c($, $, $)) { print_template |c, 'command' }
sub print_template(*@values) {
# work done here
}
say triple 'App1', 'App2', 'p';
我这里有这个功能:
my @modifiers = <command option>;
sub triple(|c(Str:D $app1!, Str:D $app2!, Str:D $key! where .chars == 1, Str:D $mod where ($mod ~~ any @modifiers) = 'command' )) {
print_template(|c);
}
sub print_template(*@values) {
...work done here...
}
我遇到的问题是,如果我在没有第 4 个参数的情况下调用它,例如 triple 'App1', 'App2', 'p';
,默认的 $mod
参数不会传递给 print_template
参数。
有办法做到这一点吗?
对于完整的上下文,这是这里的玩具程序:https://paste.debian.net/1226675/
好的,根据 IRC 中的回复,这似乎不可能。一种建议的解决方法:
sub triple(|c(Str:D $app1!,
Str:D $app2!,
Str:D $key! where .chars == 1,
Str:D $mod where ($mod ~~ any @modifiers) = 'command' )) {
my \d = \(|c[0..2], c[3] // 'command');
print_template(|d);
}
TL;DR 1.问题的解释。 2. DRY 解决方案。 3. DRYest 解决方案:parameters-capture
函数。
问题的解释
呼叫分两步进行:
构造一个呼叫,不知道哪个routine会听到这个呼叫。这包括构造调用参数的捕获。在第 2 步之前,此捕获已经完成并已除尘,不可变。
看看有哪些常规候选人可能会绑定电话。尝试将捕获绑定到他们的签名。例程签名中的某些参数可能会指定默认值,以防缺少参数。
因此,给定一个捕获 c
,您不能更改它来弥补其中不存在的任何参数,并且 Raku 不会自动创建一个新的捕获来伪装任何参数不在里面现在在里面。相反,您将不得不手动添加缺失值。
一个DRY解决方案
字符串 'command'
在您回答的建议解决方案中出现了两次。
编写 DRY 解决方案的一种方法是使用整个捕获,其中将包括所有传递的参数,然后 append 任何 parameters,其中相应的 参数 未 通过。也就是说,而不是:
my \d = \(|c[0..2], c[3] // 'command');
这样写:
my \d = \(|c, |($mod if not c[3]));
DRYest 解决方案:parameters-capture
函数
最终,您的场景需要的是一个完全忽略用于调用例程的 参数 的函数,而只是创建一个新的捕获,其中包含例程的所有 参数。然后一个人可以写,说:
print_template(|parameters-capture);
我觉得这很重要。这意味着遍历例程的参数数据。这大概会通过类似 &?ROUTINE.signature.params
的方式进行。但是 &?ROUTINE
是一个编译时变量,并且是相对于当前例程的,所以你如何在你从 例程中 调用的函数中得到它,你的参数是有兴趣吗?即使你能得到它,你如何从编译时参数数据结构到最终绑定到参数的 运行 时间值?这完全超过了我的工资等级。进行这种胆量编码可能比在 Perl 世界中要容易得多,在 Perl 世界中它意味着 C 编码,但仍然如此。
获得相同总体结果的另一种方法(可能是我要采用的方法)是将其拆分为 multi
并根据参数数量进行分派。这是一种可能的方式(将共享参数的验证移至 proto
:
my @modifiers = <command option>;
proto triple(Str:D, Str:D, Str:D $ where .chars == 1, $?) {*}
multi triple(|c($, $, $, Str:D $ where any @modifiers)) { print_template |c }
multi triple(|c($, $, $)) { print_template |c, 'command' }
sub print_template(*@values) {
# work done here
}
say triple 'App1', 'App2', 'p';