在Perl中检查函数调用返回的最有效方法

时间:2011-01-11 02:55:26

标签: perl pass-by-reference

我想将函数调用中的返回值添加到数组iff返回的内容(默认情况下不是这样,即如果我在子例程中有return语句。)

所以我正在使用unshift @{$errors}, "HashValidator::$vfunction($hashref)";,但这实际上是将函数调用的字符串添加到数组中。我也试过unshift @{$errors}, $temp if defined my $temp = "HashValidator::$vfunction($hashref)";同样的结果。 perl单行看起来会有什么效果(我知道我可以进行丑陋的多行检查,但我想学习)。

谢谢,

3 个答案:

答案 0 :(得分:2)

  

iff返回的东西(不是   默认,即如果我有回报   子程序中的语句。)

这里可能有问题。 Perl 总是返回一些东西,即使你不是故意:

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

如果没有显式返回,则sub中的最后一个表达式将用作返回值。要返回“nothing”,请使用bare return,它返回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
}

答案 1 :(得分:2)

在这种情况下,无需使用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(...)

答案 2 :(得分:1)

尝试使用eval:

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

以下内容适用于perl 5.12,并检查undef返回值:

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