评估和死亡

这是处理异常的内置方法,而不依赖于像 Try::Tiny 这样的第三方库。

my $ret;

eval {
  $ret = some_function_that_might_die();
  1;
} or do {
  my $eval_error = $@ || "Zombie error!";
  handle_error($eval_error);
};

# use $ret

我们滥用die 具有错误返回值的事实,并且整个代码块的返回值是代码块中最后一个表达式的值:

  • 如果 $ret 被成功分配,那么 1; 表达式是 eval 代码块中发生的最后一件事。因此 eval 代码块具有真值,因此 or do 块不会运行。
  • 如果 some_function_that_might_die() 做了 die,那么在 eval 代码块中发生的最后一件事就是 die。因此,eval 代码块具有错误值,并且 or do 块确实运行。
  • 必须or do 区块做的第一件事是阅读 $@。这个全局变量将保存传递给 die 的任何参数。|| "Zombie Error" 后卫很受欢迎,但在一般情况下是不必要的。

这一点很重要,因为有些并非所有代码都通过调用 die 而失败,但无论如何都可以使用相同的结构。考虑一个返回的数据库函数:

  • 成功影响的行数
  • '0 but true'如果查询成功但没有行受到影响
  • 0 如果查询不成功。

在这种情况下,你仍然可以使用相同的习语,但你必须跳过最后的 1;,这个函数必须是 eval 中的最后一个。像这样的东西:

eval {
  my $value = My::Database::retrieve($my_thing); # dies on fail
  $value->set_status("Completed");
  $value->set_completed_timestamp(time());
  $value->update(); # returns false value on fail
} or do { # handles both the die and the 0 return value
  my $eval_error = $@ || "Zombie error!";
  handle_error($eval_error);
};