2016-11-25 95 views
5

我想減弱由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

回答

3
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