#perl #module #reference #package
#perl #модуль #ссылка #пакет
Вопрос:
Я хотел использовать ссылку на функцию для динамического выполнения функций из других пакетов.
Некоторое время я пробовал разные решения для этой идеи, и, казалось, ничего не работало! Итак, я подумал о том, чтобы задать этот вопрос, и при попытке сделать это решение сработало! но я не уверен, что это правильный способ сделать это: это требует ручной работы и немного «халтурно». Можно ли это улучшить?
-
Пакет для поддержки требуемой функциональности
package Module; # $FctHash is intended to be a Look-up table, on-reception # of command.. execute following functions $FctHash ={ 'FctInitEvaluate' => amp;FctInitEvaluate, 'FctInitExecute' => amp;FctInitExecute }; sub FctInitEvaluate() { //some code for the evalute function } sub FctInitExecute() { //some code for the execute function } 1;
2. Скрипту утилиты необходимо использовать пакет, используя ссылку на функцию
use strict;
use warnings 'all';
no strict 'refs';
require Module;
sub ExecuteCommand()
{
my ($InputCommand,@Arguments) =@_;
my $SupportedCommandRefenece = $Module::FctHash;
#verify if the command is supported before
#execution, check if the key is supported
if(exists($SupportedCommandRefenece->{$InputCommand}) )
{
// execute the function with arguments
$SupportedCommandRefenece->{$InputCommand}(@Arguments);
}
}
# now, evaluate the inputs first and then execute the function
amp;ExecuteCommand('FctInitEvaluate', 'Some input');
amp;ExecuteCommand('FctInitExecute', 'Some input');
}
Но теперь, похоже, этот метод работает! Тем не менее, есть ли способ улучшить это?
Комментарии:
1. Perl — это не JavaScript. вы вводите комментарий с помощью «#», а не с помощью «//». Круглые скобки в строках с объявлениями «sub» делают не то, что вы думаете, что они делают. Устраните их, например, sub ExecuteCommand {…}
2. Префиксы амперсандов в ваших вызовах функций (
amp;ExecuteCommand(...)
) также не делают того, что вы думаете, что они делают. Устраните их тоже.3. @Dave, на самом деле, я модифицировал его код, чтобы он выглядел (а) читабельным (б) на Perl. Но теперь я сомневаюсь: может быть, это был JavaScript…
4. @Pavel: Я взглянул на исходную версию в истории изменений вопроса и, нет, это был Perl-code-trying-to-use-//-comments с самого начала. Вы не нарушали его, оно было нарушено с самого начала. 🙂
Ответ №1:
Вы можете использовать can
. Пожалуйста, смотрите perldoc UNIVERSAL
подробности.
use strict;
use warnings;
require Module;
sub ExecuteCommand {
my ($InputCommand, @Arguments) = @_;
if (my $ref = Module->can($InputCommand)) {
$ref->(@Arguments);
}
# ...
}
Ответ №2:
Вы создали довольно стандартную реализацию для использования хэша в качестве диспетчерской таблицы. Если это ваше намерение, я не вижу причин делать что-то большее, чем просто немного почистить его. can
является хорошей альтернативой, если вы пытаетесь создать что-то ОО-иш, но это не обязательно, если все, что вам нужно, это таблица поиска команд.
Вот версия, которая а) доступна для выполнения на Perl в ее нынешнем виде (ваша попытка пометить комментарии с помощью //
в версии вопроса является синтаксической ошибкой; в Perl //
это оператор «определено-или» версии 5.10 и выше, не маркер комментария) и б) имеет больший акцент на perlish:
Module.pm
package Module;
use strict;
use warnings;
use 5.010;
our $function_lookup = {
FctInitEvaluate => amp;init_evaluate,
FctInitExecute => amp;init_execute,
};
sub init_evaluate {
say 'In init_evaluate';
}
sub init_execute {
say 'In init_execute';
}
1;
script.pl
#!/usr/bin/env perl
use strict;
use warnings;
require Module;
execute_command('FctInitEvaluate', 'Some input');
execute_command('FctInitExecute', 'Some input');
sub execute_command {
my ($input_command, @arguments) = @_;
$Module::function_lookup->{$input_command}(@arguments)
if exists($Module::function_lookup->{$input_command});
}