【问题标题】:perl defensive programming (die, assert, croak)perl 防御性编程(死,断言,呱呱)
【发布时间】:2014-02-23 16:14:46
【问题描述】:

在 perl 中进行防御性编程的最佳(或推荐)方法是什么? 例如,如果我有一个必须使用(定义的)SCALAR、ARRAYREF 和可选 HASHREF 调用的 sub。

我见过的三种方法:

sub test1 {
    die if !(@_ == 2 || @_ == 3);
    my ($scalar, $arrayref, $hashref) = @_;
    die if !defined($scalar) || ref($scalar);
    die if ref($arrayref) ne 'ARRAY';
    die if defined($hashref) && ref($hashref) ne 'HASH';
    #do s.th with scalar, arrayref and hashref
}

sub test2 {
    Carp::assert(@_ == 2 || @_ == 3) if DEBUG;
    my ($scalar, $arrayref, $hashref) = @_;
    if(DEBUG) {
        Carp::assert defined($scalar) && !ref($scalar);
        Carp::assert ref($arrayref) eq 'ARRAY';
        Carp::assert !defined($hashref) || ref($hashref) eq 'HASH';
    }
    #do s.th with scalar, arrayref and hashref
}

sub test3 {
    my ($scalar, $arrayref, $hashref) = @_;
    (@_ == 2 || @_ == 3 && defined($scalar) && !ref($scalar) && ref($arrayref) eq 'ARRAY' && (!defined($hashref) || ref($hashref) eq 'HASH'))
        or Carp::croak 'usage: test3(SCALAR, ARRAYREF, [HASHREF])';
    #do s.th with scalar, arrayref and hashref
}

【问题讨论】:

  • 有不止一种方法可以做到这一点。所有方法都有其优点和缺点。有些方法比其他方法更惯用/可读/简洁/可维护。我认为下面的标题更适合这个问题:检查子例程参数的最惯用的方法是什么?
  • 您考虑过 CPAN 产品吗? Params::ValidateType::Params 看起来不错。

标签: perl assert die defensive-programming


【解决方案1】:
use Params::Validate qw(:all);

sub Yada {
   my (...)=validate_pos(@_,{ type=>SCALAR },{ type=>ARRAYREF },{ type=>HASHREF,optional=>1 });
   ...
}
【解决方案2】:

我不会使用它们中的任何一个。除了不接受很多数组和哈希引用之外,您使用的检查几乎总是多余的。

>perl -we"use strict; sub { my ($x) = @_; my $y = $x->[0] }->( 'abc' )"
Can't use string ("abc") as an ARRAY ref nda"strict refs" in use at -e line 1.

>perl -we"use strict; sub { my ($x) = @_; my $y = $x->[0] }->( {} )"
Not an ARRAY reference at -e line 1.

检查的唯一好处是您可以使用croak 在错误消息中显示调用者。


检查是否有对数组的引用的正确方法:

defined($x) && eval { @$x; 1 }

检查是否引用了哈希的正确方法:

defined($x) && eval { %$x; 1 }

【讨论】:

    【解决方案3】:

    您显示的所有选项都没有显示任何消息来给出失败的原因,我认为这是最重要的。

    最好在库子例程中使用croak 而不是die,以便从调用者的角度报告错误。

    我会将所有出现的if ! 替换为unless。前者是C程序员的习惯。

    我建议这样的事情

    sub test1 {
        croak "Incorrect number of parameters" unless @_ == 2 or @_ == 3;
        my ($scalar, $arrayref, $hashref) = @_;
        croak "Invalid first parameter" unless $scalar and not ref $scalar;
        croak "Invalid second parameter" unless $arrayref eq 'ARRAY';
        croak "Invalid third parameter" if defined $hashref and ref $hashref ne 'HASH';
    
        # do s.th with scalar, arrayref and hashref
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-26
      • 1970-01-01
      • 1970-01-01
      • 2011-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-25
      相关资源
      最近更新 更多