9

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

(通常我喜欢模棱两可,但在这种情况下,我正在生成 SQL,所以我想用 NULL 替换未定义的参数,但将 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')";
  }
}
4

5 回答 5

17

这是一个如何处理所有可能情况的示例:

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,因为它会改变,这将要求我们存储某处@_的原始大小。)@_

于 2011-11-28T17:28:00.287 回答
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

于 2011-11-28T17:27:58.337 回答
1

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

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

关于 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::ClassNULL - 原理相同 - 传入一个 undef 值以在数据库中创建一个:

my $rs = My::Schema->resultset('MyTable');
my $obj = $rs->create({
   field1 => 'VAL1',
   field2 => 'VAL2',
   field3 => undef,    # will set a `NULL` value for field3 here
});
于 2011-11-28T17:57:47.173 回答
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');
于 2013-01-29T17:20:41.483 回答
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,然后再次使用 // 运算符。)

于 2011-11-28T17:33:25.007 回答