2017-07-28 67 views
1

当数据不正确地传递给子例程时,Perl中的最佳实践是什么?如果子死亡或只是返回?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,那么脚本将继续运行,并且可能会发生奇怪的事情。

感谢

+3

@hanshenrik:我看不出有什么帮助。 – Borodin

+1

这应该是调试的一部分,并且我认为它给编码这种特定检查带来了错误的安全感。确保一个给定的参数是真的,比如说,一个数组引用仅涵盖了可能出现的一小部分错误,如果你试图以数组的形式解引用其他的东西,Perl会引发它自己的异常。到目前为止,最常见的错误大都无法检测到,例如,您的参考可能会引用具有旧数据的数组。 – Borodin

+0

在没有使整个运行无效的情况下发生代码很少见,所以用有用的信息'死'会比让程序继续并提供不正确的结果更好。但是没有任何类型检查可以提供与最小的测试程序相同的保护。这就是为什么Java和C++的详细和冗长的语法是基于一种误解。 Perl对许多事情来说都是不应该臭名昭着的,但是即使只有非常基本的类型检查,Perl也不是其中之一。 – Borodin

回答

3

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

已经有很好的讨论,但我现在找不到那些帖子。

原则,这些都是在Perl

  • 的方式来处理错误子程序

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

    • 回报 “特殊” 的价值观,像undef抛出异常,在Perl中的设备是die

    呼叫者要么检查退货,要么检测undef,要么使用eval来捕获并处理die。什么是最适合的完全取决于上下文和代码的作用。

    在现代语言中,我没有看到很多原因被限制为表示错误的“代码”(如负值)。一方面,干涉会导致合法回报,或者限制他们通过指针/引用去执行,这是一个很大的设计决定。

    返回undef通常是一个很好的中间路径方法,特别是在不太复杂的代码中。它表明了一些“失败”的子执行它的意思。然而,即使在最小的子集undef可能适合于指示结果,这是不可接受的。那么如果它也被用于糟糕的输入,我们有一个区分这些错误的问题。

    在简单的die中引发基于Perl的异常增加了更多的可能性。在复杂的代码中,您可能希望编写(或使用)一个错误处理类,以模仿来自拥有它的语言的异常处理支持,然后抛出它。

    my $error_obj = ErrorHandlingClass->new(params); 
    
    ... or die $error_obj; 
    

    然后调用代码可以分析对象。这将是最有条理的方式。

    一个不错的简单例子是Path::Tiny,在source中找到它自己的Path::Tiny::Error

    再一次,在任何一个特定情况下适合什么取决于该应用的细节。


    对直接问题的一些评论。

    die(它告诉我们什么都没有成功),无信息的消息强调了返回什么的困境。但是在这种情况下,我们如何使失败信息化?

    请注意,如果子文件返回0或空字符串,则您的or结果为die。如果我们将其替换为//(已定义或),那么对die替换为undef,如果undef也可能表示结果不合适,我们仍无法打印特定消息。

    因此,在这种情况下,您可能需要在输入错误时输入die的函数,并输入合适的消息。

    这会做调试。如果代码需要能够恢复那么您最好返回更多结构化信息 - 抛出(或返回)您要编写的错误处理类的对象。 (作为特别的权宜措施,您可以从die解析信息。)

    至于旧的纪律检查退货问题,die是一个很好的工具。没有“简单子”,这是不值得的–你不想继续出现错误,所以它可以die。而在复杂项目中错误处理比较复杂,所以我们需要更多的工具和结构,不能少。

    回想一下,异常“冒泡”,在未处理的情况下向上传播调用堆栈,die也是如此。这可以很好地用于调试,而不必在每个呼叫上都有eval。最后,大部分是调试的一部分。

    对此没有“最佳实践”。但是默认的die -ing至少是合理的。

  • +0

    实际上是否可以抓住和处理“死亡”?你可以做一些像try {die'foo';} catch($ ex){}? – hanshenrik

    +0

    @hanshenrik哦,是的,这就是Perl中的(简单) 异常处理机制。它被[eval](http://perldoc.perl.org/functions/eval.html)(它的块形式)所捕获。有一些模块可以将它包装起来,并提供'try'-style的语法,然后还有其他的方法可以超越。但它都是基于'die'-'eval'。 – zdim

    +0

    @JohnnyLoo我在你的问题上添加了一个更直接的评论部分 – zdim