Perl вызывает подпрограмму, которая существует внутри массива - PullRequest
2 голосов
/ 20 января 2012

Я пытаюсь создать конечный автомат в Perl.Для этого у меня есть массив, индексированный по statenames.Я могу положить сабы в этот массив.Вот так:

   use constant {
    stInit          => 0,
    stHeader        => 1,
    stSalesHeader   => 2,
    stCatagory      => 3,
    stData          => 4,
    stTotal         => 5,
    stError         => 6, 
};

my $state = stInit;
my @actions;

$actions[stInit] = [sub{logState("Initial state entered",2) }];
$actions[stHeader] = [sub{logState("Header state entered",2) }];
$actions[stSalesHeader] = [sub{logState("Sales header state entered",2) }];
$actions[stCatagory] = [sub{logState("Category state entered",2) }];
$actions[stData] = [sub{logState("Data state entered",2) }];
$actions[stTotal] = [sub{logState("Total state entered",2) }];

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

$actions[$state]

Но, похоже, не работает.Это возможно или я полностью выключен?

Ответы [ 5 ]

9 голосов
/ 20 января 2012

Вы действительно должны добавить

use strict;
use warnings;

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

$actions[$state][0]();

и т.д.

Но нет необходимости помещать подпрограммы в квадратные скобки, которые просто создают одноэлементный анонимный массив и добавляют дополнительный уровень индексации (отсюда [0] в приведенной выше строке кода. Если вы написали код, подобный это вместо

$actions[stInit] = sub { logState("Initial state entered", 2) };

тогда вы сможете вызывать подпрограммы с помощью

$actions[$state]();
2 голосов
/ 20 января 2012

На немного другой ноте, вы рассматривали возможность использования FSA::Rules для написания своего конечного автомата? Он довольно мощный, имеет дополнительный вывод GraphViz и позволяет довольно легко писать конечные автоматы.

1 голос
/ 22 января 2012

Прекратить создание постороннего анонимного массива, убрав квадратные скобки

$actions[stInit] = sub{logState("Initial state entered",2) };

Затем вы можете вызвать действие с помощью

$actions[stInit]();

Если у вас есть действие, сохраненное в переменной, например

my $action = $actions[$actionID];

тогда вам понадобится немного больше синтаксиса, чтобы он действительно выполнял вызов

$action->();

Опять же, вы можете просто использовать хеш вместо массива

my %actions = (
    stInit        => sub { logState("Initial state entered",2) },
    stHeader      => sub { logState("Header state entered",2) },
    stSalesHeader => sub { logState("Sales header state entered",2) },
    stCatagory    => sub { logState("Category state entered",2) },
    stData        => sub { logState("Data state entered",2) },
);

, который избавит вас от необходимости устанавливать константы сверху.Затем вы можете вызвать действия с помощью

$actions{$state}();
1 голос
/ 20 января 2012

Вы должны сделать:

&{$actions[$state][0]}

но я не уверен, почему вы используете массив ... Если у вас есть только 1 функция, то

$actions[stData] = sub{ ... }
...
&{$actions[$state]}

будет работать. Если вы действительно хотите выполнить много функций и использовать массив, то вы можете сделать:

map { &{$_}  } @{$actions[$state]};
1 голос
/ 20 января 2012

Чтобы вызвать подпрограмму из ссылки:

&{$actions[$state]}();

Однако, исходя из вашего кода, @actions не содержит ссылок на подпрограммы, а ссылается на массив для объявления подпрограммы.* сначала объявите сабы как обычно, а затем создайте @actions:

$actions[0] = \&stInit;
$actions[1] = \&stHeader;
...and so on
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...