6 perl
如果我有Perl模块之类的话
package X;
Run Code Online (Sandbox Code Playgroud)
和像这样的对象
my $x = X->new ();
Run Code Online (Sandbox Code Playgroud)
在X.pm内部,我为$x被调用编写了一个错误处理程序handle_error,我调用它
sub check_size
{
if ($x->{size} > 1000) {
$x->handle_error ();
return;
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法handle_error强制从其来电程序返回?换句话说,在这个例子中,我可以在没有实际写入的情况下进行handle_error操作吗?returncheck_sizereturn
Dav*_*man 11
回调调用堆栈的多个级别的唯一合理方法是抛出异常/死亡.
那就是说,你真的应该重新考虑你想做什么.程序员(包括你自己,从现在起六个月)将期望,当函数调用完成后,它将执行后的语句(除非抛出异常).违反这种期望会导致错误handle_error,但这些错误似乎与调用的代码有关,这handle_error使得它们极难调试.这不是一件好事.
您还假设绝对没有处理错误后继续进行的情况是合适的.硬编码这样的假设实际上是一个肯定的保证,一旦你有时间忘记它,你会遇到一个你需要在打电话后继续的情况handle_error(然后浪费大量的时间试图弄明白为什么后面的代码handle_error没有运行).
再有就是,你会假设总是想跳过后面正好在调用栈两个层次.这是另一个假设,一旦硬编码就会失败.不仅会出现调用代码应该继续的情况,还有一些情况需要在调用堆栈中向上三级.
因此,只需handle_error通过调用die而不是return将异常捕获并将异常捕获到应继续执行的适当级别.你不知道sub将被调用的每个地方,所以你无法预测它将需要多少级别.
在手头的代码中,如果只是说额外的线条return困扰你,你可以使用return $x->handle_error; 你甚至可以摆脱封闭的范围并使它在return $x->handle_error if $x->{size} > 1000; 那里 - 删除三行而不是一行,加上一对括号和两对括号作为免费奖金.
最后,我还建议更改名称handle_error以更好地反映它实际上的作用.(report_error也许?)"处理错误"通常意味着要清理以解决错误,以便继续执行.如果你希望你handle_error阻止调用它的代码继续,那么它似乎不太可能清理它以使继续成为可能,并且再一次,它将为使用此代码的未来程序员带来令人讨厌的,难以调试的意外.
您可以使用goto &NAME,从错误处理程序返回将返回到被调用的位置check_size。
sub check_size { 我的 $x = shift; # 你没有说 X.pm 中的 $x 来自哪里。
# 我认为这是调用者。
if( $x->{size} > 1000 ) {
my $sub = $x->can('handle_error');
goto $sub;
}
Run Code Online (Sandbox Code Playgroud)
}
这是有效的,因为goto &NAME将控制权转移到被调用的函数而不创建新的堆栈帧。
我用来获取对for 的can引用,以便该方法可以与重写的子类一起正常工作。handle_error$xhandle_error
不过,这个设计对我来说似乎是个坏主意。
也许这是使用异常的好地方:
use Try::Tiny;
my $x = X->new();
try { $x->check_size }
catch { $x->handle_error };
Run Code Online (Sandbox Code Playgroud)