如何区分未通过的参数和使用false值传递的参数?

时间:2011-11-28 17:18:25

标签: perl arguments undefined shift subroutine

我试图找出在没有传递参数的情况和参数传递为0的情况下在Perl中区分的最佳方法,因为它们对我来说意味着不同的东西。

(通常我喜欢歧义,但在这种情况下我生成SQL所以我想用NULL替换未定义的args,但将0保留为0。)

所以这是含糊不清的:

sub mysub {
  my $arg1 = shift;
  if ($arg1){
    print "arg1 could have been 0 or it could have not been passed.";
  }
}

到目前为止,这是我最好的解决方案......但我认为这有点难看。我想知道你是否能想到一种更清洁的方式,或者这对你来说是否合适:

sub mysub {
  my $arg1 = (defined shift) || "NULL";
  if ($arg1 ne "NULL"){
    print "arg1 came in as a defined value.";
  }
  else {
    print "arg1 came in as an undefined value (or we were passed the string 'NULL')";
  }
}

5 个答案:

答案 0 :(得分:16)

以下是如何处理所有可能情况的示例:

sub mysub {
    my ($arg1) = @_;
    if (@_ < 1) {
        print "arg1 wasn't passed at all.\n";
    } elsif (!defined $arg1) {
        print "arg1 was passed as undef.\n";
    } elsif (!$arg1) {
        print "arg1 was passed as a defined but false value (empty string or 0)\n";
    } else {
        print "arg1 is a defined, non-false value: $arg1\n";
    }
}

@_是函数的参数数组。在这里将它与1进行比较是计算数组中元素的数量。我故意避免使用shift,因为它改变@_,这将要求我们在某处保存@_的原始大小。)

答案 1 :(得分:3)

怎么样:

sub mysub {
    my ( $arg ) = @_;

    if ( @_ == 0 ) {
        print "arg did not come in at all\n";
    } elsif ( defined $arg ) {
        print "arg came in as a defined value.\n";
    } else {
        print "arg came in as an undefined value\n";
    }
}

mysub ();
mysub ( undef );
mysub ( 1 );

更新:我添加了检查是否有任何传入的内容。但是,只有在您期望单个参数时,这才有用。如果您想获得多个参数并需要区分未定义和省略的参数,请采用哈希值。

sub mysub_with_multiple_params {
    my %args_hash = @_;

    for my $expected_arg ( qw( one two ) ) {
        if ( exists $args_hash{ $expected_arg } ) {
            if ( defined $args_hash{ $expected_arg } ) {
                print "arg '$expected_arg' came in as '$args_hash{ $expected_arg }'\n";
            } else {
                print "arg '$expected_arg' came in as undefined value\n";
            }
        } else {
            print "arg '$expected_arg' did not come in at all\n";
        }
    }
}

mysub_with_multiple_params ();
mysub_with_multiple_params ( 'one' => undef, 'two' => undef );
mysub_with_multiple_params ( 'one' => 1, 'two' => 2 );

顺便说一句:如果你必须采取任何措施消毒你的护身符,不要自己动手。请查看cpan,尤其是Params::Validate

答案 2 :(得分:1)

我个人喜欢让undef代表NULL - 它匹配DBI占位符/ DBIx :: Class / SQL :: Abstract所做的事情,将其设置为字符串"NULL"的风险是您将不小心插入字符串,而不是NULL本身。

如果您使用的是最新版本的Perl(5.10或更高版本),请查看'defined-or'运算符////=,它们对于处理参数特别方便。

关于SQL,如果要生成SQL字符串,最终可能会出现这样的结果:

sub mysub {
  my ($args) = @_;
  my @fields = qw/ field1 field2 field3 /;
  my $sql = "INSERT INTO mytable (field1,field2,field3) VALUES (" .
   join(',', map { ("'".$args->{$_}."'") // 'NULL' ) } )
    .")";
  return $sql;
}

编辑(回答有关NULL和undef的内容):

将DBI句柄与占位符一起使用:

my $sth = $dbh->prepare('INSERT INTO mytable (field1,field2,field3) '.
                        'VALUES (?,?,?)');

# undef will set a NULL value for field3 here:
$sth->execute( "VAL1", "VAL2", undef );

<强> DBIx ::类

DBIx::Class - 同样的原则 - 传入一个undef值来在数据库中创建NULL

my $rs = My::Schema->resultset('MyTable');
my $obj = $rs->create({
   field1 => 'VAL1',
   field2 => 'VAL2',
   field3 => undef,    # will set a `NULL` value for field3 here
});

答案 3 :(得分:1)

唯一可以确定的方法是检查@_的长度,以查看该槽中是否有参数。当有强制性论据时,这可以被视为有点复杂,但它并非必须如此。这是许多对象访问器中使用的模式:

package Foo;

sub undef_or_unset {
    my ($self, @arg) = @_;

    return 'unset' unless @arg;
    my ($val) = @arg;

    return 'undef' unless defined $val;
    return 'defined';
}

package main;
use Test::More tests => 3;

my $foo = bless {} => 'Foo';

is($foo->undef_or_unset(), 'unset');
is($foo->undef_or_unset(undef), 'undef');
is($foo->undef_or_unset('bluh'), 'defined');

答案 4 :(得分:0)

地图是你的朋友。试试这个:

function("joe",undef); # should print "joe" and "NULL"
function("max",38);    # should print "max" and "38"
function("sue",0);     # should print "sue" and "0"   

sub function {
    my($person,$age) = map { $_ // "NULL" } @_;
    print "person: $person\n";
    print "age:    $age\n";
}

为了添加更多颜色,我已成为使用哈希作为代码清晰度的参数并消除记住命令排序的重要性的粉丝。所以重写它看起来像这样:

function2(person=>"joe",age=>undef); # should print "joe" and "NULL"
function2(person=>"max",age=>38);    # should print "max" and "38"

sub function2 {
    my(%args) = map { $_ // "NULL" } @_;
    print "person: $args{person}\n";
    print "age:    $args{age}\n";
}

(更新:正确处理0然后再使用//运算符。)