Самый эффективный способ проверки возврата из вызова функции в Perl - PullRequest
0 голосов
/ 11 января 2011

Я хочу добавить возвращаемое значение из вызова функции в массив, если что-то возвращается (не по умолчанию, т. Е. Если в подпрограмме есть оператор return.)

, поэтому яиспользуя unshift @{$errors}, "HashValidator::$vfunction($hashref)";, но это фактически добавляет строку вызова функции в массив.Я также пытался unshift @{$errors}, $temp if defined my $temp = "HashValidator::$vfunction($hashref)"; с тем же результатом.Как бы выглядел Perl One-Liner, который делает это эффективно (я знаю, что могу сделать некрасивую многострочную проверку, но я хочу научиться)

Спасибо,

Ответы [ 3 ]

2 голосов
/ 11 января 2011

если что-то возвращается (не по умолчанию, т.е. если у меня есть возврат оператор в подпрограмме.)

Здесь может быть гоча. Perl всегда возвращает что-то, даже если вы не хотите:

my $failures = 0;
sub word_to_number {
    my $_ = shift;
    /one/ and return 1;
    /two/ and return 2;
    ++$failures; # whoops, equivalent to return ++$failures
}

Последнее выражение в подпрограмме используется в качестве возвращаемого значения, если нет явного возврата. Чтобы вернуть «ничего», используйте «голый» возврат, который возвращает undef или пустой список, в зависимости от контекста:

my $failures = 0;
sub word_to_number {
    my $_ = shift;
    /one/ and return 1;
    /two/ and return 2;
    ++$failures;
    return;
}

Это поведение действительно полезно для таких вещей, как сортировка:

my @results = sort { $a->name cmp $b->name } @list;

где мы прошли в анонимной подпрограмме:

{
    $a->name cmp $b->name # equivalent to return $a->name cmp $b->name
}
2 голосов
/ 11 января 2011

В этом случае нет необходимости использовать строковую форму eval (или любую другую форму в этом отношении).Это не только медленно, но и может молча перехватывать ошибки и может привести к выполнению ненадежного кода, если используется с испорченным вводом.Чтобы написать вызов виртуальной функции в Perl, вы можете либо напрямую работать с таблицей символов, либо использовать символическую ссылку:

use 5.010;
use warnings;
use strict;

{package HashValidator;
    sub test_ok   {exists $_[0]{ok}}
    sub test_fail {exists $_[0]{fail}}
}


my $hashref = {ok => 1};
my $errors;

for my $vFunction qw(test_ok test_fail) {

    # to call the function:
    say "glob deref: $vFunction: ", $HashValidator::{$vFunction}->($hashref);
    {no strict 'refs';
    say "symbolic:   $vFunction: ", &{"HashValidator::$vFunction"}($hashref)}

    # to conditionally use the result (if it is a true boolean value):
    if (my $ret = $HashValidator::{$vFunction}->($hashref)) {
        push @$errors, $ret;
    }

    # or to keep the function call in list context:
    push @$errors, grep $_, $HashValidator::{$vFunction}->($hashref);

    # or to golf it:
    push @$errors, $HashValidator::{$vFunction}->($hashref) || ();
}

say @$errors.': ', join ', ' => @$errors;

, которая печатает:

glob deref: test_ok: 1
symbolic:   test_ok: 1
glob deref: test_fail: 
symbolic:   test_fail: 
3: 1, 1, 1

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

$obj->$vMethod(...)
1 голос
/ 11 января 2011

попробуйте использовать eval:

push @{$errors}, eval "HashValidator::$vfunction($hashref)"

Следующее работает для меня с Perl 5.12 и проверяет неопределенные возвращаемые значения:

my $foo = "foo";
my $val = eval "Foo::$foo()"
push @arry,$val if ($val);
...