Я сохраняю имя подпрограммы, которую я хочу вызвать во время выполнения в переменной под названием $action. Затем я использую это для вызова этого суб в нужное время:
&{\&{$action}}();
Прекрасно работает. Единственное, что мне не нравится, это то, что это уродливо, и каждый раз, когда я это делаю, я чувствую себя обязанным добавить комментарий для следующего разработчика:
# call the sub by the name of $action
Кто-нибудь знает более красивый способ сделать это?
ОБНОВЛЕНИЕ: Идея здесь заключалась в том, чтобы избежать необходимости вести таблицу отправки каждый раз, когда я добавлял новый вызываемый суб, поскольку я являюсь единственным разработчиком, я не беспокоюсь о других программистах, следующих или не следующих "правилам". Пожертвовать немного безопасности для моего удобства. Вместо этого мой диспетчерский модуль проверил бы $action, чтобы убедиться, что 1) это имя определенной подпрограммы, а не вредоносный код для запуска с eval, и 2) что он не будет запускать какой-либо суб, помеченный знаком подчеркивания, который будет помечены как внутренние субтитры в соответствии с этим соглашением об именах.
Любые мысли об этом подходе? Подпрограммы "Список белых списков" в таблице диспетчеризации - это то, что я все время буду забывать, и мои клиенты предпочли бы, чтобы я ошибался на стороне "он работает", чем "он нечестивый". (очень ограниченное время для разработки приложений)
ЗАКЛЮЧИТЕЛЬНОЕ ОБНОВЛЕНИЕ: Я все-таки решил, что на диспетчерском столе я решил. Хотя мне было бы любопытно, если кто-нибудь, кто прочитает этот вопрос, когда-либо пытался покончить с этим и как он это сделал, я должен поклониться коллективной мудрости здесь. Спасибо всем, много отличных ответов.
Вместо того, чтобы хранить имена подпрограмм в переменной и вызывать их, лучший способ сделать это - использовать хеш ссылок подпрограмм (иначе известный как отправка таблица.)
my %actions = ( foo => \&foo,
bar => \&bar,
baz => sub { print 'baz!' }
...
);
Затем вы можете легко позвонить справа:
$actions{$action}->();
Вы также можете добавить некоторую проверку, чтобы убедиться, что $action
является допустимым ключом в хеше и т.д.
В общем, вам следует избегать символических ссылок (что вы делаете сейчас), поскольку они вызывают всевозможные проблемы. Кроме того, при использовании реальных ссылок подпрограммы будут работать с strict
.
$actions{$action}->($parmVariable,11,'a');
Параметры должны быть согласованы во всех возможных вызываемых подпрограммах, хотя значения, конечно, могут быть получены из переменных.
Просто &$action()
, но обычно лучше использовать coderefs с самого начала или использовать хеш диспетчера. Например:
my $disp = {foo => \&some_sub, bar => \&some_other_sub };
$disp->{'foo'}->();
А? Вы можете просто сказать
$action->()
Пример:
sub f { return 11 }
$action = 'f';
print $action->();
$ perl subfromscalar.pl
11
Конструкции вроде
'f'->() # equivalent to &f()
также работают.
use strict
(и, конечно, вы делаете), вам нужно будет no strict 'refs'
use strict qw(vars subs)
no strict 'refs'
или просто use strict qw(vars subs)
чтобы использовать этот синтаксис.
Я не уверен, что понимаю, что вы имеете в виду. (Я думаю, что это еще одна из недавней группы "Как я могу использовать переменную как имя переменной?", Но, возможно, нет.)
В любом случае вы должны иметь возможность назначить всю подпрограмму переменной (в качестве ссылки), а затем вызвать ее прямо:
# create the $action variable - a reference to the subroutine
my $action = \&preach_it;
# later - perhaps much later - I call it
$action->();
sub preach_it {
print "Can I get an amen!\n"
}
Самое главное: почему вы хотите использовать переменную в качестве имени функции. Что произойдет, если это будет "eval"? Есть ли список функций, которые можно использовать? Или это может быть любая функция? Если список существует - сколько времени он занимает?
Как правило, наилучшим способом обработки таких случаев является использование таблиц отправки:
my %dispatch = (
'addition' => \&some_addition_function,
'multiplication' => sub { $self->call_method( @_ ) },
);
А потом просто:
$dispatch{ $your_variable }->( 'any', 'args' );
Я делаю что-то подобное. Я разделил его на две строки, чтобы сделать его немного более узнаваемым, но это не намного красивее.
my $sub = \&{$action};
$sub->();
Я не знаю более правильного или красивого способа сделать это. Для чего это стоит, у нас есть производственный код, который делает то, что вы делаете, и он работает без необходимости отключать use strict
.
$sub->($parmVariable,11,'a');
__PACKAGE__->can($action)->(@args);
Для получения дополнительной информации о can(): http://perldoc.perl.org/UNIVERSAL.html
Каждый пакет в Perl уже является хеш-таблицей. Вы можете добавлять элементы и ссылаться на них обычными хэш-операциями. В общем случае нет необходимости дублировать функциональность с помощью дополнительной хеш-таблицы.
#! /usr/bin/perl -T
use strict;
use warnings;
my $tag = 'HTML';
*::->{$tag} = sub { print '<html>', @_, '</html>', "\n" };
HTML("body1");
*::->{$tag}("body2");
Код печатает:
<html>body1</html> <html>body2</html>
Если вам нужно отдельное пространство имен, вы можете определить выделенный пакет.
Для получения дополнительной информации см. perlmod.
Я сделал это следующим образом:
@func = qw(cpu mem net disk);
foreach my $item (@func){
$ret .= &$item(1);
}
Используйте
&{\&{$action}}();
Или используйте eval для выполнения функции:
eval("$action()");
Я использовал это: он работает для меня.
(\$action)->();
Или вы можете использовать 'do', очень похожее на предыдущие сообщения:
$p = do { \&$conn;};
$p->();
Если это только в одной программе, напишите функцию, которая вызывает подпрограмму, используя имя переменной, и только нужно документировать ее/извиниться один раз?