Perl - 处理传递给子组件的无效数据的最佳实践

问题描述 投票:0回答:1

当数据被错误地传递给子例程时,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
1个回答
3
投票

这完全属于如何处理一般子程序中的错误的问题。

原则上,这些是处理子程序中无法自行恢复的错误的方法

  • 返回代码,其中一些指示错误

  • 返回“特殊”值,就像 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.

© www.soinside.com 2019 - 2024. All rights reserved.