2

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

我见过的三种方法:

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
}
4

3 回答 3

3

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

>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 }
于 2014-02-23T17:33:41.523 回答
3
use Params::Validate qw(:all);

sub Yada {
   my (...)=validate_pos(@_,{ type=>SCALAR },{ type=>ARRAYREF },{ type=>HASHREF,optional=>1 });
   ...
}
于 2014-02-23T17:39:58.267 回答
1

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

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

我会用 替换所有出现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
}
于 2014-02-23T17:23:26.390 回答