2011-05-30 88 views
3

考虑到retrys给定函数某些给定的次数,如果函数抛出下面的包装函数(不知道为什么格式是靠不住的):这个perl包装函数可以扩展到任何输入函数吗?


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

} 

这怎么可能延长,使的返回值无论返回什么样的值,参数函数都可以正确地得到支持。例如,这个函数不会正确传递数组。你不能只返回$ fun - >(),因为return只会将你带出eval块。

+0

你能提供更多关于这个问题的细节吗?例如,当返回值是一个数组时,会发生什么? – Greg 2011-05-30 23:54:48

+0

@greg如果返回值是一个数组,那么$ ret被赋值为最后一个元素 – frankc 2011-05-31 00:19:43

+0

函数的返回值从不是数组。它可能是一个列表或对数组的引用。 – tadmc 2011-05-31 03:37:14

回答

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([email protected]){ 
     print "Error attemping cmd: [email protected]\n"; 
    } 
    else{ 
     if ($array_wanted) { 
      return @ret; 
     } 
     else { 
      return $ret; 
     } 
    } 
    }while($times > 0); 
    return; 

} 

我相信一个怪物的Perl黑客可以找到一种方法来加强这件事,但是这是基本的想法。

+1

我们写的几乎一样,直到文档链接:)我会收回我的答案,并upvote你的。 – 2011-05-31 00:07:59

+2

如果你想成为恶魔,你可以将'$ ret'改为'$ ret [0]'并完全移除标量'$ ret'变量。另外,您可能想要解释'wantarray'返回'undef'的场景。 – 2011-05-31 00:23:59

+0

@Emilio:伟大头脑思考的+1 +1 – Nemo 2011-05-31 00:29:02

6

基本相同的答案尼莫,但也有一些改进:

  • 更安全的异常处理。
  • 最后一次尝试的例外未被捕获。
  • 发送到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([email protected], "Retrying...\n"); 
    } 

    return $func->(@_); 
} 

无效上下文获取作为无效上下文传播,但这可能是可以接受的。如果不是,则很容易调整。

相关问题