2012-03-14 61 views
1

我完全困惑。這裏是我的代碼:爲什麼兩個分支似乎都執行?

use strict; 
use warnings; 
use Test::More; 

subtest 'huh?' => sub { 
    my $i = 0; 
    eval { 
     $i++; 
    } || do { 
     $i++; 
    }; 
    is($i, 1, "only execute one branch (i: $i)"); 
}; 

&done_testing(); 

這是我的測試輸出(用時5.12的activeperl運行的Mac OS X):

not ok 1 - only execute one branch (i: 2) 
    # Failed test 'only execute one branch (i: 2)' 
    # at test.pl line 14. 
    #   got: '2' 
    #  expected: '1' 
    1..1 
    # Looks like you failed 1 test of 1. 
not ok 1 - huh? 
# Failed test 'huh?' 
# at test.pl line 15. 
1..1 
# Looks like you failed 1 test of 1. 

這到底是怎麼回事?我預計只有第一個分支才能運行,因爲沒有任何die s。但它看起來像兩個分支都被執行。

回答

5

$i++返回之前的值$i增量。所以,因爲它是0,那麼它是錯誤的。並且eval返回最後一個評估結果,也就是那個假值。然後它繼續嘗試下一個塊(因爲它應該)。

如果您只想要第一個分支,您需要將增量表達式「增量,,然後返回」,如此eval { ++$i }

現在看到的最好的方式,如果失敗的eval是不返回1,但做到以下幾點:

  1. 本地化[email protected](或$English::EVAL_ERROR
  2. EVAL
  3. 測試[email protected]

    local [email protected]; 
    eval { $some_sub->(); }; 
    croak("Failed in evaluate: [email protected]") if [email protected]; 
    
+0

啊...所以當我使用'eval'來捕獲異常時,我應該始終確保它返回一個真值,以免在'eval'內部拋出異常? – 2012-03-14 20:09:20

+0

@MattFenwick,如果你打算用'||'或者'or'測試返回,那麼是的。我要更新我的答案。 – Axeman 2012-03-14 20:12:03

+1

如果你在修正bug之前運行一個perl版本,'if $ $'語句有機會運行之前'$ @'可以在'DESTROY'塊中清除。 'eval {...; 1}或呱呱叫......'不會受到這個錯誤的影響。 – 2012-03-14 21:47:22

2

eval { $i ++ }返回的結果與$i ++返回的結果相同,即$i在增加之前的值。由於您將$i設置爲0,因此它將返回0,該值爲false,這意味着||的右操作數也會被計算。

我想你混淆了結果eval,它被保存在[email protected]eval返回(這簡直是對包含的表達式的結果)與die結果。

+0

是的,我想我不得不重構我的代碼庫來檢查'$ @'而不是'eval'的返回值。 – 2012-03-14 20:10:58

+0

或使用Try :: Tiny :) – 2012-03-15 00:01:19

+0

@briandfoy:是的,[TIMTOWTDI](http://en.wikipedia.org/wiki/There's_more_than_one_way_to_do_it) – 2012-03-15 00:16:10

相關問題