Об использовании массива функций в Perl
Мы пытаемся создать API для автоматической поддержки commit() и rollback(), чтобы нам больше не приходилось с этим связываться. Исследуя, мы обнаружили, что с помощью eval {}
это путь
За eval {}
чтобы знать, что делать, я подумал о том, чтобы дать API массив функций, которые он может выполнять с foreach
без API, не нужно ничего интерпретировать. Однако эта функция может быть в другом пакете.
Позвольте мне уточнить на примере:
sub handler {
use OSA::SQL;
use OSA::ourAPI;
my @functions = ();
push(@functions, OSA::SQL->add_page($date, $stuff, $foo, $bar));
my $API = OSA::ourAPI->connect();
$API->exec_multi(@functions);
}
Вопрос в том, возможно ли выполнить функции в @functions
Внутри OSA::ourAPI
, даже если наш API не имеет use OSA::SQL
, Если нет, было бы возможно, если бы я использовал ссылку на массив вместо массива, учитывая, что указатель будет указывать на известную функцию внутри памяти?
Примечание. Это основная идея, на которой мы хотим основывать более сложную окончательную версию.
1 ответ
Вы НЕ добавляете указатель на функцию в свой массив. Вы добавляете возвращаемое значение вызова подпрограммы add_page(). У вас есть 3 решения для этого:
А. Вам нужно будет хранить (в
@functions
) массив arrayrefs вида[\&OSA::SQL::add_page, @argument_values]
это означает, что вы передаете фактическую ссылку на подпрограмму (называемую статически); а затем exec_multi сделает что-то вроде (синтаксис может быть не на 100% правильным, так как здесь 4 утра)sub exec_multi {my ($ class, $ funcs) = @_; foreach my $ f (@ $ funcs) {my ($ func, @args) = @ $ f; my $ res = & $ func (@args); выведите "RES:$res\n"; } }
Просто для повторения, это вызовет отдельные подпрограммы в статической версии (
OSA::SQL::add_page
), например, БЕЗ передачи имени пакета в качестве первого параметра в качестве вызова классаOSA::SQL->add_page
было бы. Если вы хотите последнее, посмотрите следующее решение.Б. Если вы хотите вызывать ваши подпрограммы в контексте класса (как в вашем примере, другими словами, с именем класса в качестве первого параметра), вы можете использовать предложение ysth в комментарии.
Вам нужно будет хранить (в
@functions
) массив arrayrefs вида[sub { OSA::SQL->add_page(@argument_values) }]
это означает, что вы передаете ссылку на подпрограмму, которая, в свою очередь, будет вызывать то, что вам нужно; а затем exec_multi сделает что-то вроде (синтаксис может быть не на 100% правильным, так как здесь 4 утра)sub exec_multi { my ($ class, $ funcs) = @_; foreach my $ f (@ $ funcs) { my ($ func) = @ $ f; my $ res = & $ func (); выведите "RES: $ res \ n"; } }
C. Вам нужно будет хранить (в
@functions
) массив arrayrefs вида[ "OSA::SQL", "add_page", @argument_values]
это означает, что вы передаете имя пакета и функции; а затем exec_multi сделает что-то вроде (синтаксис может быть не на 100% правильным, так как здесь 4 утра)my ($ package, $ sub, @args) = @ {$ functions [$ i]}; нет строгих "ссылок"; $ Пакет ->$ (суб @args); используйте строгие "ссылки";
Если я правильно понял ваш вопрос, то вам не нужно беспокоиться о том, использует ли наш API OSA::SQL, поскольку ваш основной код уже импортирует его.
Однако, поскольку - в #1B - вы будете передавать список пакетов в exec_multi в качестве первых элементов каждого arrayref, вы можете сделать "
require $package; $package->import();
"в exec_multi. Но опять же, это совершенно не нужно, если ваш вызов обработчика уже потребовал и загрузил каждый из этих пакетов. И чтобы сделать это правильно, вам нужно передать список параметров вimport()
также. НО ЧТО ГГГГГГ?:)