Как выполнять функции из пакетов, используя ссылку на функцию в perl?

#perl #module #reference #package

#perl #модуль #ссылка #пакет

Вопрос:

Я хотел использовать ссылку на функцию для динамического выполнения функций из других пакетов.

Некоторое время я пробовал разные решения для этой идеи, и, казалось, ничего не работало! Итак, я подумал о том, чтобы задать этот вопрос, и при попытке сделать это решение сработало! но я не уверен, что это правильный способ сделать это: это требует ручной работы и немного «халтурно». Можно ли это улучшить?

  1. Пакет для поддержки требуемой функциональности

     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});
}