В Perl, как я могу вызвать метод, имя которого у меня есть в строке? - PullRequest
6 голосов
/ 27 апреля 2010

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

sub verify_attribute {
    my ($object, $attribute_method, $wanted_value) = @_;
    if ( call_method($object, $attribute_method) ~~ $wanted_value ) {
        return 1;
    }
    else {
        return;
    }
}

Затем я могу перебрать хеш, ключами которого являются имена методов доступа, а значениями являются значения, которые я ищу для этих атрибутов. Например, если этот хеш называется %wanted, я мог бы использовать такой код, чтобы найти нужный объект:

my $found_object;
FINDOBJ: foreach my $obj (@list_of_objects) {
    foreach my $accessor (keys %wanted) {
        next FINDOBJ unless verify_attribute($obj, $accessor, $wanted{$accessor});
    }
    # All attrs verified
    $found_object = $obj;
    last FINDOBJ;
}

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

Ответы [ 2 ]

5 голосов
/ 27 апреля 2010
my $found_object;
FINDOBJ: foreach my $obj (@list_of_objects) {
  foreach my $accessor (keys %wanted) {
    next FINDOBJ unless $obj->$accessor() == $wanted{$accessor};
  }
  # All attrs verified
  $found_object = $obj;
  last;
}

Да, вы можете вызывать методы таким образом.Никакой строки (или любой другой) eval не участвует.Кроме того, замените == на eq или =~ в зависимости от типа данных ...

Или, для некоторых дополнительных кредитов, сделайте это функциональным способом: (все () должно быть действительночасть List :: Util!)

use List::Util 'first';

sub all (&@) {
  my $code = shift;
  $code->($_) || return 0 for @_;
  return 1;
}

my $match = first {
                    my $obj = $_;
                    all { $obj->$_ == $attrs{$_} }
                      keys %wanted
                  } @list_of_objects;

Обновление: по общему признанию, первое решение является менее запутанным, поэтому оно предпочтительнее.Но когда кто-то отвечает на вопросы, вы должны добавить немного сахара, чтобы сделать его интересным и для себя!; -)

0 голосов
/ 02 октября 2012

Функциональный способ это круто, но для чайников вроде меня действуют правила:

test.pl

#!/usr/bin/perl -l
use F;
my $f = F->new();

my $fun = 'lol'; # method of F

eval '$f->'.$fun.'() '; # call method of F, which name is in $fun var

F.pm

package F;

sub new
{
    bless {};
}


sub lol
{
    print "LoL";
}
1;

[root @ ALT-24 root] # perl test.pl

LoL

...