Подтвердить что ты не робот

Как я могу элегантно назвать подпрограмму Perl, чье имя хранится в переменной?

Я сохраняю имя подпрограммы, которую я хочу вызвать во время выполнения в переменной под названием $action. Затем я использую это для вызова этого суб в нужное время:

&{\&{$action}}();

Прекрасно работает. Единственное, что мне не нравится, это то, что это уродливо, и каждый раз, когда я это делаю, я чувствую себя обязанным добавить комментарий для следующего разработчика:

# call the sub by the name of $action

Кто-нибудь знает более красивый способ сделать это?


ОБНОВЛЕНИЕ: Идея здесь заключалась в том, чтобы избежать необходимости вести таблицу отправки каждый раз, когда я добавлял новый вызываемый суб, поскольку я являюсь единственным разработчиком, я не беспокоюсь о других программистах, следующих или не следующих "правилам". Пожертвовать немного безопасности для моего удобства. Вместо этого мой диспетчерский модуль проверил бы $action, чтобы убедиться, что 1) это имя определенной подпрограммы, а не вредоносный код для запуска с eval, и 2) что он не будет запускать какой-либо суб, помеченный знаком подчеркивания, который будет помечены как внутренние субтитры в соответствии с этим соглашением об именах.

Любые мысли об этом подходе? Подпрограммы "Список белых списков" в таблице диспетчеризации - это то, что я все время буду забывать, и мои клиенты предпочли бы, чтобы я ошибался на стороне "он работает", чем "он нечестивый". (очень ограниченное время для разработки приложений)


ЗАКЛЮЧИТЕЛЬНОЕ ОБНОВЛЕНИЕ: Я все-таки решил, что на диспетчерском столе я решил. Хотя мне было бы любопытно, если кто-нибудь, кто прочитает этот вопрос, когда-либо пытался покончить с этим и как он это сделал, я должен поклониться коллективной мудрости здесь. Спасибо всем, много отличных ответов.

4b9b3361

Ответ 1

Вместо того, чтобы хранить имена подпрограмм в переменной и вызывать их, лучший способ сделать это - использовать хеш ссылок подпрограмм (иначе известный как отправка таблица.)

my %actions = ( foo => \&foo,
                bar => \&bar,
                baz => sub { print 'baz!' } 
                ... 
              );

Затем вы можете легко позвонить справа:

$actions{$action}->();

Вы также можете добавить некоторую проверку, чтобы убедиться, что $action является допустимым ключом в хеше и т.д.

В общем, вам следует избегать символических ссылок (что вы делаете сейчас), поскольку они вызывают всевозможные проблемы. Кроме того, при использовании реальных ссылок подпрограммы будут работать с strict.

Ответ 2

Просто &$action(), но обычно лучше использовать coderefs с самого начала или использовать хеш диспетчера. Например:

my $disp = {foo => \&some_sub, bar => \&some_other_sub };
$disp->{'foo'}->();

Ответ 3

А? Вы можете просто сказать

    $action->()

Пример:

    sub f { return 11 }
    $action = 'f';
    print $action->();


    $ perl subfromscalar.pl
    11

Конструкции вроде

    'f'->()     # equivalent to   &f()

также работают.

Ответ 4

Я не уверен, что понимаю, что вы имеете в виду. (Я думаю, что это еще одна из недавней группы "Как я могу использовать переменную как имя переменной?", Но, возможно, нет.)

В любом случае вы должны иметь возможность назначить всю подпрограмму переменной (в качестве ссылки), а затем вызвать ее прямо:

# 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"
}

Ответ 5

Самое главное: почему вы хотите использовать переменную в качестве имени функции. Что произойдет, если это будет "eval"? Есть ли список функций, которые можно использовать? Или это может быть любая функция? Если список существует - сколько времени он занимает?

Как правило, наилучшим способом обработки таких случаев является использование таблиц отправки:

my %dispatch = (
   'addition' => \&some_addition_function,
   'multiplication' => sub { $self->call_method( @_ ) },
);

А потом просто:

$dispatch{ $your_variable }->( 'any', 'args' );

Ответ 6

Я делаю что-то подобное. Я разделил его на две строки, чтобы сделать его немного более узнаваемым, но это не намного красивее.

my $sub = \&{$action};
$sub->();

Я не знаю более правильного или красивого способа сделать это. Для чего это стоит, у нас есть производственный код, который делает то, что вы делаете, и он работает без необходимости отключать use strict.

Ответ 8

Каждый пакет в 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.

Ответ 9

Используйте

&{\&{$action}}();

Или используйте eval для выполнения функции:

eval("$action()");

Ответ 10

Я сделал это следующим образом:

@func = qw(cpu mem net disk);
foreach my $item (@func){
    $ret .= &$item(1);
}

Ответ 11

Если это только в одной программе, напишите функцию, которая вызывает подпрограмму, используя имя переменной, и только нужно документировать ее/извиниться один раз?

Ответ 12

Я использовал это: он работает для меня.

(\$action)->();

Или вы можете использовать 'do', очень похожее на предыдущие сообщения:

$p = do { \&$conn;}; 
$p->();