Ответ 1
Я думаю, Sub::Current устранит вашу проблему.
В целях обучения я собираюсь с идеей создания управляемые событиями в Perl, и заметил, что было бы неплохо, если бы подпрограмма, которая была зарегистрирована в качестве обработчика событий, может, при сбое, просто назначьте другой вызов самому себе на более поздний срок. До сих пор у меня есть придумайте что-то вроде этого:
my $cb;
my $try = 3;
$cb = sub {
my $rc = do_stuff();
if (!$rc && --$try) {
schedule_event($cb, 10); # schedule $cb to be called in 10 seconds
} else {
do_other_stuff;
}
};
schedule_event($cb, 0); # schedule initial call to $cb to be performed ASAP
Есть ли способ, чтобы код внутри суб-канала мог получить доступ к coderef к этому sub, чтобы я мог обойтись без использования дополнительной переменной? Я бы хотел назначьте начальный вызов следующим образом.
schedule_event( sub { ... }, 0);
Сначала я подумал об использовании caller(0)[3]
, но это только дает мне
имя функции, (__ANON__
если нет имени), а не ссылку на код
к которому прикреплен блокнот.
Я думаю, Sub::Current устранит вашу проблему.
Чтобы получить ссылку на текущую подпрограмму без использования дополнительной переменной, вы можете использовать инструмент из функционального программирования Y-combinator, который в основном абстрагирует процесс создания закрытия. Вот версия с персиком:
use Scalar::Util qw/weaken/;
sub Y (&) {
my ($code, $self, $return) = shift;
$return = $self = sub {$code->($self, @_)};
weaken $self; # prevent a circular reference that will leak memory
$return;
}
schedule_event( Y { my $self = shift; ... }, 0);
__SUB__
добавлено в 5.16, обеспечивая это удобство использования.
Если вы не измените значение $cb
еще раз, вы можете использовать это. Если нет, определите скаляр, чтобы его удерживать, и не изменяйте его снова. Например:
my $cb = do {
my $sub;
$sub = sub { contents using $sub here }
}
Используя комбинатор с фиксированной запятой, вы можете написать функцию $cb, как если бы первым аргументом была сама функция:
sub U {
my $f = shift;
sub { $f->($f, @_) }
}
my $cb = sub {
my $cb = shift;
...
schedule_event(U($cb), 10);
...
}
schedule_event(U($cb), 0);