Ослабление снимков с использованием 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 [...]

И вот моя попытка Sub:: Quote:

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 реализация сложна; Я вполне уверен, что это невозможно с текущим кодом, но я бы хотел, чтобы показалось, что это неправильно.

1 ответ

Решение
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. Когда вы создаете копию (сильной или слабой) ссылки, это сильная ссылка.
Другие вопросы по тегам