10

以下代码(一个简化的示例,我实际上是在遍历对象列表并尝试捕获异常)通过转到 for 列表中的下一项来执行错误处理。它可以工作,但会警告在 catch 子例程中使用循环控制语句:

use strict;
use warnings;
use Try::Tiny;
use 5.010;

NUM: for my $num (1 .. 10) { 
  try { 
    if ($num == 7) { 
      die 'ugly number'; 
    } 
  } catch { 
    chomp;
    say qq/got "$_"/; 
    next NUM; 
  }; 
  say qq/number $num/; 
}

输出:

number 1
number 2
number 3
number 4
number 5
number 6
got "ugly number at testtry.pl line 9."
Exiting subroutine via next at testtry.pl line 14.
Exiting subroutine via next at testtry.pl line 14.
number 8
number 9
number 10

我可以看到解决它的两种方法——在这个用法的范围内关闭警告,使用范围内的无警告块,或者将错误消息复制到一个临时变量并在 catch 块之外检查它/下一个。前者可能有我忽略的问题,而后者则稍微扩展了错误处理。哪个是首选,还是我忽略了另一种方式?

4

4 回答 4

7

在 catch 块内,放一个no warnings 'exiting'. 这将禁用警告。和pragma 只是为了帮助您,当它们妨碍您时strictwarnings请随意禁用它们。

perldiag页面列出了内置的警告和错误类别。您可以通过禁用此类别来查看所有将被静音的消息,并决定是否值得。

编辑:

你可以利用一个成功的return ,但在错误tryundef你会得到catch块的值。这使我们能够:

NUM: for my $num (1 .. 10) { 
  try {
    die 'ugly number' if $num == 7;
  } catch { 
    chomp;
    say qq/got "$_"/; 
    return 1;       # return some true value
  } and next NUM;   # go to next iteration here, outside the try/catch
  say qq/number $num/; 
}

但是,我发现no warnings解决方案更优雅,也更明显。

于 2013-05-21T14:14:06.830 回答
2

这种情况的正确解决方案——可能是你试图解决的更一般的情况——是将只有在没有错误时才应该发生的东西放入try块中,而不是依赖于显式循环控制。看起来像这样:

for my $num (1 .. 10) { 
  try { 
    if ($num == 7) { 
      die 'ugly number'; 
    } 
    say qq/number $num/; 
  } catch { 
    chomp;
    say qq/got "$_"/;
  }; 
}

last是实际上需要特别注意的循环控制语句,因为它要做的不仅仅是跳过循环体。但考虑

try {
  for my $num (1 .. 10) { 
    try {
      die 'ugly number' if $num == 7;
      die 'early exit' if $num == 9;
      say qq/number $num/; 
    } catch {
      die $_ if /^early exit/;
      chomp;
      say qq/got "$_"/;
    }; 
  }
};
于 2013-05-21T19:31:29.950 回答
0

基本上,我正在寻找以下流量控制。我只是不喜欢仅仅为了进行下一个 NUM 错误处理而确定 $e 的范围。

use strict;
use warnings;
use Try::Tiny;
use 5.010;

NUM: for my $num (1 .. 10) { 
  my $e;
  try { 
    if ($num == 7) { 
      die 'ugly number'; 
    } 
  } catch { 
    chomp;
    say qq/got "$_"/; 
    $e = $_; 
  }; 
  if ($e) {
    next NUM;
  }
  say qq/number $num/; 
}
于 2013-05-21T14:03:03.957 回答
0

另一种解决方法,虽然可能只对这个简化的例子有用,而不是在你的整个程序中,是避免next将代码放在模具之后的指令,比如:

use strict;
use warnings;
use Try::Tiny;
use 5.010;

for my $num (1 .. 10) { 
  try { 
    if ($num == 7) { 
      die 'ugly number'; 
    }   
    say qq/number $num/; 
  } catch { 
    chomp;
    say qq/got "$_"/; 
    #next NUM; 
  }; 
  #say qq/number $num/; 
}

它产生:

number 1
number 2
number 3
number 4
number 5
number 6
got "ugly number at script.pl line 11."
number 8
number 9
number 10
于 2013-05-21T13:55:31.877 回答