【问题标题】:Returning error messages from perl subroutines从 perl 子例程返回错误消息
【发布时间】:2011-04-18 22:39:37
【问题描述】:

这是从 perl 中的子例程返回错误消息的好方法吗?

sub some_subroutine{
    # do something
    $something = 14;

    if(1 == 2){
        $_ = "This should not be happening!";
        return undef;
    }
    return $something;
}

my $ret=some_subroutine();
print "ERROR: $_" unless(defined $ret);

代码运行正常(在平行世界,1 == 2),但是使用$_返回错误信息是个好办法吗?我没有找到任何关于将$_ 用于此类目的的文档。

谢谢!

【问题讨论】:

    标签: perl


    【解决方案1】:

    $_ 不是一个好的机制,因为有很多其他东西使用和设置它。

    您可以设置一些其他全局变量,例如 $Error,但最好的方法是抛出异常。然后用户不必总是检查,然后忘记,它只是发生了。在 Perl 中,使用“die”生成异常。 die 将接受一个字符串或一个对象。有许多模块可以使抛出异常更容易,包括 Exception::ClassException::SimpleOuchautodie

    您可以使用eval {} 捕获异常,但有a number of problems with that,因此您应该使用Try::Tiny 之类的东西。

    【讨论】:

    • 当错误不是“异常”时,您是否发现返回一些错误/未定义状态在语义上没有价值?例如,如果您期望文件可能不存在,那么返回错误状态而不是抛出异常在语义上不是更有意义吗?这是一个小问题,我知道......
    • @SoloBold 不要太纠结于“异常”的确切含义。如果子程序不能完成它的工作,这是一个例外情况。如果这意味着调用者不能期望正常的返回值,这是一个例外情况。如果您编写一个检查文件是否存在的子例程,那么如果文件不存在也不是例外。如果你编写一个读取和解析文件的例程,如果文件不存在,它应该抛出异常。
    • ...如果较大的系统在缺少该文件的情况下可以接受,您可以在其周围放置一个包装器,检查文​​件是否存在,如果不存在则返回和空结构。最后,程序员会忘记编写错误处理代码,但您必须故意忽略异常。它针对懒惰进行了优化。
    【解决方案2】:

    使用全局变量来保存错误消息并不陌生。例如,内置函数使用$!,DBI 使用$DBI::errstr。但是你继承了使用全局变量的所有问题。信号处理程序需要对它们进行本地化,析构函数可以破坏它们,多线程问题等。

    在我看来,抛出异常(例如使用die)是一种更常见的选择。

    无论你做什么,都不要使用$_。它通常与某些东西有别名,因此使用它可能会产生意想不到的后果。

    【讨论】:

      【解决方案3】:

      您可以做的一件事情使这稍微好一点,就是在错误/未定义的结果上简单地return;。在某些情况下,return undef; 可以评估为true。您可以查看Perl Best Practices 的错误处理一章,因为它涵盖了这一点,并有其他很好的指导。

      例如,如果:

      my $ret=some_subroutine();
      print "ERROR: $_" unless(defined $ret);
      

      变成

      my @ret=some_subroutine();         # oops!
      print "ERROR: $_" unless(defined $ret);
      

      您有一个可能难以追踪的奇怪错误(未捕获错误),而如果您从 some_subroutine return; 得到:

      my @ret=some_subroutine();         # oops!
      print "ERROR: $_" unless($ret);    # but error is still caught
      

      此外,对于应该返回列表的函数:

      my @ret=some_other_subroutine();    # OK
      print "ERROR: $_" unless($ret);     # error will be caught if you "return;"
      
      # ... but later ...
      
      my $ret=some_other_subroutine();    # oops!
      print "ERROR: $_" unless($ret);     # if you "return;" $ret will equal 0
                                          # (the length of the returned list)
                                          # and the error will be caught
      

      因此,虽然还有其他模式可以从函数返回错误/未定义状态,但始终使用 return; 允许对几乎所有函数使用一种模式,无论是返回适当的值还是需要检查错误状态。

      【讨论】:

      • 这是 PBP 中不良建议的一个示例。如果子例程通常返回标量,则在错误时返回 undef,而不是空列表。
      • 这很有趣,但你没有说服我。如果在列表上下文中调用函数,返回一个元素列表(undef) 似乎同样糟糕。该子例程可能会返回一个标量,但是如果您从列表上下文中调用它,如果我理解正确,您将不会得到一个标量。当您 return; 时,您始终可以确定 !foo() 为真,但在您 return undef; 时则不然
      • 但是,我的意思是,如果我错了,一定要说服我。我试图在答案中更好地解释。
      • 也许一个明确的案例会有所帮助? sub show_bar { my %args=@_; print "bar: $args{'bar'}\n" } sub get_foo { return; } show_bar( 'foo' => get_foo(), 'bar' => 'barbar' ) 这里的 get_foo,按名称和用法,显然应该返回一个标量,但在错误情况下它不会,这不仅会导致错误,而且会导致无法直接追溯到 get_foo 调用。这种情况在到处使用return; 的人身上很常见。
      【解决方案4】:

      这完全取决于您期望从错误处理程序中看到什么行为。在 perl 中使用diewarn 是很常见的,以防发生运行时错误/警告。

      看看这个关于 perl 错误处理的教程:http://www.tutorialspoint.com/perl/perl_error_handeling.htm

      【讨论】:

        【解决方案5】:

        对于 Web 服务,您可以编写一个子例程来打印自定义错误响应(40x 错误等)。

        【讨论】:

          猜你喜欢
          • 2015-01-19
          • 2021-09-01
          • 2014-07-02
          • 2016-01-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-07-04
          • 1970-01-01
          相关资源
          最近更新 更多