当数据被错误地传递给子例程时,Perl 中的最佳实践是什么?潜艇应该死还是回来?
这是我通常做的事情
my @text = ('line 1', 'line 2');
print_text(\@text)
or die "ERROR: something went wrong in the sub";
sub print_text{
my ($aref_text) = @_;
return unless ref($aref_text) eq "ARRAY";
print "$_\n" for @{$aref_text};
return 1;
}
这里,如果传递的输入无效,子程序就会返回,并且它希望调用者像这里一样检查错误。我想知道在底层“死”是否总是更好的做法。在大型脚本中,我害怕这样做,因为我不想仅仅因为一些简单的子程序失败而终止整个脚本。
另一方面,我害怕返回,因为如果调用者忘记检查 sub 是否返回 true,那么脚本将继续运行,并且可能会发生奇怪的事情。
谢谢
这完全属于如何处理一般子程序中的错误的问题。
原则上,这些是处理子程序中无法自行恢复的错误的方法
返回代码,其中一些指示错误
返回“特殊”值,就像 Perl 中的
undef
抛出异常,Perl 中的一个装置是 die(来自模块的croak/confess)
调用者要么检查返回,要么测试
undef
,或者使用eval
†来捕获并处理die
。最合适的完全取决于上下文和代码的作用。
我认为现代语言没有太多理由限制指示错误的“代码”(如负值)。一方面,要么干扰合法的返回,要么限制它们通过指针/引用,这是一个重大的设计决策。
返回
undef
通常是一个很好的中间方法,特别是在不太复杂的代码中。它表明子系统在执行其预期功能时出现了一些“失败”。然而,即使在最小的子中,undef
也可能适合指示不可接受的结果。那么,如果它也用于错误的输入,我们就会遇到区分这些失败的问题。
抛出异常,基于 Perl 中简单的
die
,增加了更多的可能性。在复杂的代码中,您可能很想编写(或使用)一个错误处理类,该类模仿拥有该类的语言的更复杂的异常处理支持,然后抛出该错误处理类。
my $error_obj = ErrorHandlingClass->new( params );
... or die $error_obj;
然后调用代码就可以分析该对象了。这将是最结构化的方法。一个很好且简单的例子是
Path::Tiny,在其 source
中找到了自己的
Path::Tiny::Error
。
再次强调,什么适合任何一种特定情况取决于该应用程序的详细信息。
die
中的无信息消息强调了返回什么的困境(它没有告诉我们什么失败了)。但在这种情况下,我们如何让失败提供信息呢?请注意,如果子返回
or
或空字符串,则
die
会生成
0
。如果我们将其替换为
//
(定义或),那么对于
die
上的
undef
,如果
undef
也可能表示错误结果,我们仍然无法打印特定消息。因此,在这种情况下,您可能希望该函数在输入错误时
die
,并提供合适的消息。这样可以在出现问题后进行调试。如果代码需要能够“恢复”,那么您最好返回更多结构化信息——抛出(或返回)您编写的错误处理类的对象。 (作为临时的权宜之计,您可以解析来自
die
的消息。)
对于检查退货的纪律这个古老的问题,
die
是一个很好的工具。没有“简单子
”是不值得的——你不想继续出错,所以
die
没关系。在复杂的项目中,错误处理更加复杂,因此我们需要更多工具和结构,而不是更少。回想一下,异常会“冒泡”,如果未处理,则会向上传播调用堆栈,
die
也是如此。这可以很好地用于调试,而无需在每次调用时都使用 eval
。最后,这大部分都是调试的一部分。
对此没有“最佳实践”。但默认的
die
-ing 是相当合理的。†
try
-catch
风格的异常处理 (
die
) 支持。它在 5.34.0 中作为实验性引入
,但他们建议现在使用Feature::Compat::Try。这是 移植自 Syntax::Keyword::Try.