2016-11-25 11 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 
} 

출력 :

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 
Can't use an undefined value as a subroutine reference [...] 

그리고 여기 내 하위 :: 견적 시도의 예를 들어, 여기에 비 인용 대안이다

foo 
foo 

분명히 캡처 된 $y은 약화되지 않습니다. 캡처 된 변수를 약화시키기 위해 생성 된 코드를 변경하는 방법이 있습니까?

문서가 희박하며 Sub::Quote 구현이 복잡합니다. 나는 이것이 현재 코드에서 가능하지 않다는 것을 확신하지만, 잘못된 것으로 보여지고 싶다.

+0

'약화'는 실제로 무엇을합니까? 그것이 효과가 있다면'$ y'를'약하게 만든 '직후에'$ y'가'undef'가 될 것이라고 예상했을 것입니다. – melpomene

+0

@melpomene, CV에 대한 두 번째 참조가 있습니다 (Devel :: Peek의'Dump'를 사용하여 보았습니다). /// 즉,'$ y = undef; '는 OP가 예상하는대로 실제로 서브를 해제하지 않는다는 것을 의미합니다. 데모에 영향을주지 않고'약화 '에 대한 호출을 삭제할 수 있습니다. – ikegami

+0

@ikegami 두 번째 참조는 optree 자체에 있다고 가정 할 것입니다. 서브가 클로저가 아니기 때문입니다. 따라서 컴파일 중에 생성되어 영원히 유지됩니다. – melpomene

답변

3
my $bar = quote_sub('&$y', { '$y' => \$y }); 

대략

my $bar = eval(q{ my $y = $y; sub { &$y } }); 

동일하다 (더 않지만, 그 비트는이 질문에 부적합하다). 보시다시피, 서브 [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