2011-05-30 82 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->(@_); 
} 

無效上下文獲取作爲無效上下文傳播,但這可能是可以接受的。如果不是,則很容易調整。

相關問題