这个perl包装函数可以扩展为使用任何输入函数吗?

时间:2011-05-30 23:46:50

标签: perl eval

考虑以下包装器函数,如果函数抛出(不确定为什么格式化不稳定),则会给定函数重试一定次数:


sub tryit{
    my $fun = shift;
    my $times = shift;
    my @args = @_;
    my $ret;
    do{  
    $times--;
    eval{
        $ret = $fun->(@args);
    };
    if($@){
        print "Error attemping cmd: $@\n";
    }
    else{
         return $ret;
    }
    }while($times > 0);
    return;

}

如何扩展,以便无论返回什么类型的值,都可以正确地调整参数函数的返回值?例如,此函数不会正确传递数组。你不能只返回$ fun->()因为返回只会让你离开eval块。

2 个答案:

答案 0 :(得分:6)

与Nemo相同的基本答案,但有一些改进:

  • 更安全的异常处理。
  • 没有抓住最后一次尝试的例外。
  • 发送给STDERR的错误。
  • 删除了额外的换行符。
  • 清洁循环。
  • 更好的变量名称。

wantarray将为您提供所需的信息。

sub tryit {
    my $func        = shift;
    my $attempts    = shift;
    my $list_wanted = wantarray;
    my @rv;
    for (2..$attempts) {
        if (eval{
            if ($list_wanted) {
                @rv = $func->(@_);
            } else {
                $rv[0] = $func->(@_);
            }
            1  # No exception
        }) {
            return $list_wanted ? @rv : $rv[0];
        }

        warn($@, "Retrying...\n");
    }

    return $func->(@_);
}

Void上下文作为void上下文传播,但这可能是可以接受的。如果没有,它很容易调整。

答案 1 :(得分:5)

您可以使用wantarray执行此操作。 (对我来说格式很难,对不起)

sub tryit{
    my $fun = shift;
    my $times = shift;
    my @args = @_;
    my $array_wanted = wantarray;
    my $ret;
    my @ret;
    do{  
    $times--;
    eval{
        if ($array_wanted) {
            @ret = $fun->(@args);
        }
        else {
            $ret = $fun->(@args);
        }
    };
    if($@){
        print "Error attemping cmd: $@\n";
    }
    else{
         if ($array_wanted) {
             return @ret;
         }
         else {
             return $ret;
         }
    }
    }while($times > 0);
    return;

}

我确信一个怪物Perl黑客可以找到一种方法来收紧它,但这是基本的想法。