Как я могу просмотреть список функций в Perl? - PullRequest
4 голосов
/ 05 августа 2009

У меня есть список функций в Perl. Пример:

my @funcs = qw (a b c)

Теперь все они принадлежат этому модулю Foo :: Bar :: Stix. Я хотел бы назвать их итеративно в цикле:

foreach $func (@funcs) {
    Foo::Bar::Stix::$func->(%args)
}

где args - это хэш аргументов. Однако я продолжаю получать эту ошибку: «Bad name after :: ...» в строке, содержащей Foo :: Bar :: Stix :: $ func -> (% args) Как мне исправить эту ошибку?

a b и c не являются функциональными объектами, а являются строками

Ответы [ 5 ]

9 голосов
/ 05 августа 2009

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

#!/usr/bin/perl

use strict;
use warnings;

my %func_refs = (
    'a' => \&Foo::Bar::Stix::a,
    'b' => \&Foo::Bar::Stix::b,
    'c' => \&Foo::Bar::Stix::c
);

foreach my $func_ref ( values %func_refs ) {
    print $func_ref->( "woohoo: " ), "\n";
}

{
  package Foo::Bar::Stix;

  sub a {
    my $arg = shift;
    return $arg . "a";
  }

  sub b {
    my $arg = shift;
    return $arg . "b";
  }

  sub c {
    my $arg = shift;
    return $arg . "c";
  }
}

Если по какой-то причине вы не можете сохранить имена, попробуйте следующее:

my $package    = "Foo::Bar::Stix";
my @func_names = qw/ a b c /;
foreach my $func_name (@func_names) {
    my $str = &{ "$package\::$func_name" }( "woohoo: " );
    print $str, "\n";
}

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

Кроме того, большинство людей, работающих с Perl, используют его как Perl, а не как PERL. Вот вопрос Stackoverflow по этому вопросу:

Как мне прописать Perl?

3 голосов
/ 05 августа 2009

Плохой ответ: используйте символьную ссылку:

for $func (@funcs) {
    &{"Foo::Bar::Stix::$func"}(\%args);
}

Хороший ответ: используйте таблицу отправки:

my %call_func = (
    'a' => \&Foo::Bar::Stix::a,
    'b' => \&Foo::Bar::Stix::b,
    'c' => \&Foo::Bar::Stix::c,
);
...
for $func (@funcs) {
    $call_func{$func}->(\%args);
}
1 голос
/ 13 августа 2009

Вы можете использовать can

my @funcs = qw (a b c)
foreach $func (@funcs) {
    Foo::Bar::Stix->can($func)->(%args)
}
1 голос
/ 05 августа 2009

Небольшое изменение синтаксиса даст вам то, что вы хотите

Foo::Bar::Stix->$func(%args)

Хотя это передаст имя пакета в качестве первого параметра.

0 голосов
/ 05 августа 2009

Вы можете получить к нему доступ через специальную переменную %Foo::Bar::Stix::. Это дает полный доступ непосредственно к таблице символов. Вы также заметите, что он работает в строгом режиме.

#! /usr/bin/env perl
use strict;
use warnings;

{
  package Foo::Bar::Stix;
  sub a{ print "sub a\n" }
  sub b{ print "sub b\n" }
  sub c{ print "sub c\n" }
}

my @funcs = qw' a b c ';
my %args;

for my $func (@funcs) {
  $Foo::Bar::Stix::{$func}->(%args); # <====
}

Другой вариант:

my $symbol_table = $::{'Foo::'}{'Bar::'}{'Stix::'};

my %funcs = (
  # we only want the CODE references
  'a' => *{ $symbol_table->{'a'} }{'CODE'},
  'b' => *{ $symbol_table->{'b'} }{'CODE'},
  'c' => *{ $symbol_table->{'c'} }{'CODE'},
);

for my $func (@funcs) {
  $funcs{$func}->(%args); # <====
}

Если вы собираетесь делать это для большого количества подпрограмм, я бы загрузил переменную %funcs.

my %funcs;
BEGIN{
  my $symbol_table = $::{'Foo::'}{'Bar::'}{'Stix::'};

  for my $name (qw' a b c '){
    $funcs{$name} = *{ $symbol_table->{$name} }{'CODE'};
  }
}

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

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

my %funcs = (
  'a' => sub{ print "sub a\n" },
  'b' => sub{ print "sub b\n" },
  'c' => sub{ print "sub c\n" },
);

Примечание: вы можете заменить "my %funcs" на "our %funcs"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...