Perl 给定许多要测试定义的变量,如何(轻松地)找出未定义的变量?

Perl 给定许多要测试定义的变量,如何(轻松地)找出未定义的变量?,perl,Perl,今天我看到了这段代码: if ( not defined($reply_address) or not defined($from_name) or not defined($subject) or not defined($date) ) { die "couldn’t glean the required information!"; } (Jeffrey Friedl,“掌握正则表达式”,第59页,第3版) 我想“我怎

今天我看到了这段代码:

if (    not defined($reply_address) 
     or not defined($from_name) 
     or not defined($subject) 
     or not defined($date) )
{ 
  die "couldn’t glean the required information!"; 
}
(Jeffrey Friedl,“掌握正则表达式”,第59页,第3版)

我想“我怎么知道哪个变量出错了?”

当然,如果只有4个变量需要测试,如上例所示,可以得出:

if ( not defined $reply_address ) 
{ 
  die "\$reply_address is not defined" 
}
elsif ( not defined $from_name )
{
  die "\$from_name is not defined"
}
elsif ...
但是如果有14个变量呢?还是40。。。? 我们仍然需要检查所有这些,手动测试每一个


有没有一种更简短、更“神奇”的方法来判断哪个变量未定义?

您可以创建一个表来简化一点:

use strict;
use warnings;

my $reply_address = "xyz";
my $from_name;
my $subject = "test";
my $date;

my @checks = (
    [\$reply_address, '$reply_adress'],
    [\$from_name, '$from_name'],
    [\$subject, '$subject'],
    [\$date, '$date'],
);

for my $check (@checks) {
    if (not defined ${$check->[0]}) {
        die $check->[1] . " is not defined";
    }
}

可以使用字符串eval完成:

use strict;
use warnings;

my ($reply_address, $from_name, $subject, $date) = ('', '', undef, '');

for my $var (qw(reply_address from_name subject date)) {
    my $defined;
    eval "\$defined = defined \$$var";
    die "eval failed: $@" if $@;
    die "\$$var is not defined" unless $defined;
}

您可以随心所欲地使用它们,尽管使用它们通常不是一个好主意,而且只能使用包变量,而不能使用词汇范围的变量(词汇范围的变量比包变量更受欢迎——请参阅二者的简要比较)

您也可以使用通用代码循环检查所有变量:

#!/usr/bin/env perl

use strict;
use warnings;

use 5.014;

my($foo2) = 1;
my($bar2) = undef;
my($baz2) = 3;

foreach my $vardef (["foo2", $foo2], ["bar2", $bar2], ["baz2", $baz2]) {
    my($name) = $vardef->[0];
    my($value)  = $vardef->[1];

    warn "$name: is not defined" unless defined $value;
    say "$name: <$value>";
}
如果测试真的像
die If那样简单!定义
然后我可能会列出它们:

#!/usr/bin/env perl

use strict;
use warnings;

use 5.014;

my($foo4) = 1;
my($bar4) = undef;
my($baz4) = 3;

die qq([ERROR] \$foo4 not defined\n) unless defined $foo4;
die qq([ERROR] \$bar4 not defined\n) unless defined $bar4;
die qq([ERROR] \$baz4 not defined\n) unless defined $baz4;
这给了我们:

[ERROR] $bar4 not defined
最后一种方法非常简单明了。如果测试没有这么简单,那么我会选择第二种方法。如果你担心一个包含40个(甚至14个)这种性质的检查的列表,那么我会看看设计


关于第一个选项的一个非常复杂的版本,请参见此代码示例,但允许使用词汇范围内的变量。

我没有足够神奇的答案,但是
die'$reply\u address未定义',除非定义了$reply\u address
将是一个更清晰的代码示例。说真的,这是一个非常糟糕的主意。你可以用一个散列来做完全相同的想法,然后跳过
eval
。很少有好主意涉及
eval
。这不应该有2张赞成票。如果你能解释一下为什么这个想法“非常糟糕”,这会对我有所帮助。不是一般的,而是具体的用法。因为对字符串使用
eval
允许用户在系统上执行任意代码。虽然您的特定案例看起来足够安全,但您永远不知道其他用户在使用您的代码时会引入哪些安全漏洞。随着安全漏洞的扩大,这是一个很大的漏洞。另外,因为这正是散列的工作方式,所以可以使用一个字符串作为键来获取值。例如,
die“$var未定义”,除非定义了$data{$var}
foo2: <1>
bar2: is not defined at ./test.pl line 29.
Use of uninitialized value $value in concatenation (.) or string at ./test.pl line 30.
bar2: <>
baz2: <3>
#!/usr/bin/env perl

use strict;
use warnings;

use 5.014;

my($vars) = {
    foo3 => 1,
    bar3 => undef,
    baz3 => 3,
};

foreach my $name (sort keys %$vars) {
    my($value)  = $vars->{$name};

    warn "$name: is not defined" unless defined $value;
    say "$name: <$value>";
}
bar3: is not defined at ./test.pl line 42.
Use of uninitialized value $value in concatenation (.) or string at ./test.pl line 43.
bar3: <>
baz3: <3>
foo3: <1>
#!/usr/bin/env perl

use strict;
use warnings;

use 5.014;

my($foo4) = 1;
my($bar4) = undef;
my($baz4) = 3;

die qq([ERROR] \$foo4 not defined\n) unless defined $foo4;
die qq([ERROR] \$bar4 not defined\n) unless defined $bar4;
die qq([ERROR] \$baz4 not defined\n) unless defined $baz4;
[ERROR] $bar4 not defined