在
@L_403_0@的讨论让我想知道:其他编程语言的异常系统有什么Perl的缺乏?
Perl内置的异常是有点特别的,因为他们像Perl 5对象系统一样,作为一个事后的想法,它们被重新绑定,并且它们重载了没有专门用于异常的其他关键字(eval和die)。
与具有内置try / throw / catch类型语法的语言相比,语法可能有点丑陋。我通常这样做:
eval { do_something_that_might_barf(); }; if ( my $err = $@ ) { # handle $err here }
有几个CPAN模块提供语法糖添加try / catch关键字和允许容易声明异常类层次结构和whatnot。
我看到Perl的异常系统的主要问题是使用特殊的全局$ @持有当前的错误,而不是一个专门的捕获类型的机制,可能更安全,从范围的角度,虽然我从来没有亲自经历任何问题$ @得到munged。
解决方法
一些异常类,例如
Error,不能处理try / catch块内的流控制。这会导致微妙的错误:
use strict; use warnings; use Error qw(:try); foreach my $blah (@somelist) { try { somemethod($blah); } catch Error with { my $exception = shift; warn "error while processing $blah: " . $exception->stacktrace(); next; # bzzt,this will not do what you want it to!!! }; # do more stuff... }
解决方法是使用状态变量并检查try / catch块之外,这对我看起来可怕的像臭的n00b代码。
另外两个“陷阱”在错误(这两个都让我很伤心,因为他们是可怕的调试,如果你没有遇到这个)
use strict; use warnings; try { # do something } catch Error with { # handle the exception }
看起来很明智,对吧?此代码编译,但导致奇怪和不可预测的错误。问题是:
> use错误qw(:try)被省略,所以try {} …块将被错误解释(你可能会看到一个警告,这取决于你的代码的其余部分)
>在catch块后面缺少分号!不直观的控制块不使用分号,但事实上try是一个原型方法调用。
哦,是的,这也提醒我,因为try,catch等是方法调用,这意味着这些块内的调用堆栈不会是你期望的。 (实际上有两个额外的堆栈级别,因为Error.pm内部调用)因此,我有一些模块充满了样板代码,这只是增加了杂乱:
my $errorString; try { $x->do_something(); if ($x->failure()) { $errorString = 'some diagnostic string'; return; # break out of try block } do_more_stuff(); } catch Error with { my $exception = shift; $errorString = $exception->text(); } finally { local $Carp::CarpLevel += 2; croak "Could not perform action blah on " . $x->name() . ": " . $errorString if $errorString; };