我一直在读关于Captures的内容,这一段引起了我的兴趣:
在签名内部,可以通过在sigilless参数前加上垂直条|来创建Capture。这会将参数列表的其余部分打包到该参数中。
这听起来很像**@
(非扁平化)邋,,所以这个编制了这个测试代码:
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
作为一种邋??是否有不利的一面?我是否简化了比较?
Capture
有两个插槽,包含VM级数组(位置参数)和散列(命名参数)。它的结构非常便宜,并且 - 由于|c
风格的论证在内部的各个部分非常普遍 - 已经得到了很好的优化。由于捕获参数会覆盖位置参数和命名参数,因此将以静默方式忽略任何命名参数。对于方法而言,这可能不是什么问题,其中不需要的命名参数无论如何都将被静默放置到%_
中,但如果在sub
上使用此构造,则可能需要考虑,因为它不是纯粹的优化:它会改变行为。
**@c
案例分配了一个Array
,然后为每个传递的值分配一个Scalar
容器,将它们放入Scalar
容器中,并将那些Scalar
容器放入Array
中。这是一项合理的额外工作。
这里没有考虑另一个案例,就是这个案例:
sub test3(**@c is raw){
1;
}
这将List
放置在@c
中,并将其元素设置为直接引用所传递的内容。这比没有is raw
的情况便宜一点。从理论上讲,它可能表现得和|c
这样的捕获参数一样好 - 如果不是更好的话。它可能只是需要有人在编译器上进行深入研究它为什么还没有。
总而言之,如果不关心强制执行项目化和/或有一个可变的Array
传入参数,那么添加is raw
可能是一个比选择一个捕获参数更好的优化赌注:参数处理语义更接近,它已经快一点,将允许对于更自然的代码,并且未来有可能像|c
一样快,如果不是更快。