2012-03-14 49 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

相关问题