弱化捕获使用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的实现很复杂;我确信目前的代码是不可能的,但我很乐意被证明是错误的。

+0

那里的'weaken'实际上做了什么吗?如果它有效,我会希望'$ y'在'weaken $ y'之后变成'undef'。 – melpomene

+0

@melpomene,还有第二个引用CV(如使用Devel :: Peek的'Dump'看到的),但我不知道它是什么。 ///这就是说,这意味着'$ y = undef;'实际上并没有释放子任务,因为OP期望。在不影响演示的情况下,可以删除对'weaken'的调用。 – ikegami

+0

@ikegami我假设第二个引用是在选择本身,因为sub不是闭包,所以它可能是在编译期间创建的,并且只是永远存在。 – melpomene

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 }); 

你可以倾诉的模块的维护者有关添加,将导致使用别名的选项。


  1. 当您创建的(强或弱)的参考副本,这是一个有力的参考。
+0

更新了我的答案。 – ikegami