Об использовании массива функций в 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() также. НО ЧТО ГГГГГГ?:)

Другие вопросы по тегам