弱化捕获使用Sub :: Quote
问题描述:
我想减弱由Sub::Quote生成的代码中捕获的变量。例如,这里的不带引号的替代:弱化捕获使用Sub :: Quote
use 5.10.0;
use Scalar::Util qw[ weaken ];
{
my $s = 'foo';
my $x = sub { say $s };
weaken(my $y = $x);
my $bar = sub { &$y };
&$bar;
$x = undef;
&$bar
}
和输出:
foo
Can't use an undefined value as a subroutine reference [...]
这是我的子::报价的尝试:
use 5.10.0;
use Sub::Quote;
use Scalar::Util qw[ weaken ];
{
my $s = 'foo';
my $x = sub { say $s };
weaken(my $y = $x);
my $bar = quote_sub('&$y', { '$y' => \$y });
&$bar;
$x = undef;
&$bar;
}
和输出:
foo
foo
显然捕获的$y
没有被削弱。有没有更改生成的代码来减弱捕获的变量的方法?
文档很少,而且Sub::Quote
的实现很复杂;我确信目前的代码是不可能的,但我很乐意被证明是错误的。
答
my $bar = quote_sub('&$y', { '$y' => \$y });
是大致相同
my $bar = eval(q{ my $y = $y; sub { &$y } });
(它确实多,但这些比特是不相关的这个问题)。正如您所看到的那样,这会为sub [1]创建新的强烈参考。通过使用
my $bar = eval(q{ my $y_ref = \$y; sub { &{ $$y_ref } } });
这样就可以实现:
作为一种变通方法,您可以添加一个间接层
my $bar = quote_sub('&{$$y_ref}', { '$y_ref' => \\$y });
世上本没有如果$y
任何问题由Sub :: Quote创建的是您的$y
的别名。这可以通过使用Data :: Alias或5.22中引入的实验性功能来实现。
这可以通过以下证明:
{
package Sub::Quote;
my $sub = sub {
my ($from, $captures, $indent) = @_;
join(
'',
"use feature qw(refaliasing);\n",
"no warnings qw(experimental::refaliasing);\n",
map {
/^([\@\%\$])/
or croak "capture key should start with \@, \% or \$: $_";
(' ' x $indent).qq{\\my ${_} = \\${1}{${from}->{${\quotify $_}}};\n};
} keys %$captures
)
};
no warnings qw(redefine);
*capture_unroll = $sub;
}
my $bar = quote_sub('&$y', { '$y' => \$y });
你可以倾诉的模块的维护者有关添加,将导致使用别名的选项。
- 当您创建的(强或弱)的参考副本,这是一个有力的参考。
+0
更新了我的答案。 – ikegami
那里的'weaken'实际上做了什么吗?如果它有效,我会希望'$ y'在'weaken $ y'之后变成'undef'。 – melpomene
@melpomene,还有第二个引用CV(如使用Devel :: Peek的'Dump'看到的),但我不知道它是什么。 ///这就是说,这意味着'$ y = undef;'实际上并没有释放子任务,因为OP期望。在不影响演示的情况下,可以删除对'weaken'的调用。 – ikegami
@ikegami我假设第二个引用是在选择本身,因为sub不是闭包,所以它可能是在编译期间创建的,并且只是永远存在。 – melpomene