像糊涂一样使用捕获

时间:2019-04-16 13:38:01

标签: capture perl6

我一直在阅读有关Captures的内容,这一段吸引了我:

  

在签名内部,可以通过在没有签名的前缀之前创建捕获   带竖线|的参数。这包装了其余的   参数列表中的参数。

这听起来很像**@(非扁平化)的混混,所以这就是下面的测试代码:

my $limit=1_000_000;
my @a=1 xx 10000;
my @b=-1 xx 10000;

sub test1(|c){
    1;
};

sub test2(**@c){
    1;
};
{ 
    for ^$limit {
        test1(@b,@a);
    }
    say now - ENTER now;
}
{
    for ^$limit {
        test2(@b,@a);
    }
    say now - ENTER now;
}

样本运行给出了每个测试块的持续时间:

0.82560328                                                                                                                                                                                                                                                                                                         
2.6650674 

Capture显然具有性能优势。以这种方式将Capture用作粗鲁内容有不利之处吗?我是否简化了比较?

1 个答案:

答案 0 :(得分:10)

A Capture has two slots, holding a VM-level array (positional arguments) and hash (named arguments). It is quite cheaply constructed, and - since |c style arguments are quite common in various bits of the internals - has been well optimized. Since a capture parameter slurps up both positional and named arguments, any named arguments will be silently ignored. That's probably not much of an issue for methods, where unrequired named arguments will be silently placed into %_ anyway, but might be a consideration if using this construct on a sub, since it's not a pure optimization: it changes behavior.

The **@c case allocates an Array, and then allocates a Scalar container for each of the passed values, placing them into the Scalar containers and those Scalar containers into the Array. That's a reasonable amount of extra work.

There's another case not considered here, which is this one:

sub test3(**@c is raw){
    1;
}

That places a List in @c, and sets its elements to refer directly to the things that were passed. This is a bit cheaper than the case without is raw. In theory, it could probably perform as well as - if not better than - a capture parameter like |c; it probably just needs somebody working on the compiler to have a dig into why it doesn't yet.

In summary, if not caring about enforcing itemization and/or having a mutable Array of incoming arguments, then adding is raw is probably a better optimization bet than picking a capture parameter: the argument processing semantics are closer, it's already a bit faster, will allow for more natural code, and has future potential to be every bit as fast as, if not faster, than |c.