如何区分未传递的参数和传递错误值的参数?

发布于 2024-12-18 07:58:10 字数 621 浏览 2 评论 0原文

我试图找出在 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')";
  }
}

I am trying to figure the best way to differeniate in Perl between cases where an argument has not been passed, and where an argument has been passed as 0, since they mean different things to me.

(Normally I like the ambiguity, but in this case I'm generating SQL so I want to replace undefined args with NULL, but leave 0 as 0.)

So this is the ambiguity:

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

And so far, this is my best solution... but I think it is a little ugly. I'm wondering if you can think of a cleaner way or if this looks OK to you:

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')";
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

望喜 2024-12-25 07:58:10

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

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

Here's an example of how you can handle all the possible cases:

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";
    }
}

(@_ is the array of arguments to your function. Comparing it to 1 here is counting the number of elements in the array. I'm intentionally avoiding shift, as it alters @_, which would require us to store the original size of @_ somewhere.)

自找没趣 2024-12-25 07:58:10

怎么样:

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

What about:

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 );

Update: I added the check if there was anything passed in at all. But that can only be useful if you are expecting a single parameter. If you would like to get multiple params and need to differentiate between undefined and omitted parameters, take a hash.

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 );

And btw: If you have to do any steps to sanitize your params, don't do it yourself. Have a look at cpan and especially Params::Validate

甜警司 2024-12-25 07:58:10

就我个人而言,我喜欢保留 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::Class

DBIx::Class - 相同的原理 - 传入一个未定义在数据库中创建 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
});

personally I like keeping undef to represent NULLs - it matches what DBI placeholders/DBIx::Class/SQL::Abstract all do, and the risk with setting it to be the string "NULL" is that you will accidentally insert the string, rather than NULL itself.

If you're using a recent version of Perl (5.10 or above), then check out the 'defined-or' operators // and //= which are particularly handy for processing arguments.

regarding the SQL, if you want to generate the SQL string, you could end up with something like this:

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

edit (to answer the bit about NULL and undef):

Using DBI handles with placeholders:

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::Class

DBIx::Class - same principle - pass in an undef value to create a NULL in the database:

my $rs = My::Schema->resultset('MyTable');
my $obj = $rs->create({
   field1 => 'VAL1',
   field2 => 'VAL2',
   field3 => undef,    # will set a `NULL` value for field3 here
});
死开点丶别碍眼 2024-12-25 07:58:10

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

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');

The only way to be sure is to inspect the length of @_ to see if there was an argument in that slot. This can be seen as a little complicated when there are also mandatory arguments, but it doesn't have to be. Here's a pattern used in a lot of object accessors:

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');
酒中人 2024-12-25 07:58:10

地图是你的朋友。尝试一下:

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,然后再次使用 // 运算符。)

map is your friend. Try this:

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";
}

To add a little more color, I've become a fan of using a hash as the arguments for code clarity and to remove the importance of remembering arugment ordering. So rewritten it would look like this:

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";
}

(Updated: to handle 0 correctly and then again to use the // operator.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文