给定一些变量来测试定义性,如何(轻松地)找出未定义的变量?
Given a number of variables to test for definedness, how to (easily) find out the one which was left undefined?
今天看到这段代码:
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...?
还需要全部过一遍,逐个手动测试?
有没有更短、更“神奇”的方法来判断哪个变量未定义?
您可以创建一个 table 来稍微简化一下:
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";
}
}
可以用字符串求值来完成:
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;
}
你可以随心所欲地使用symbolic references, though using them is generally not a great idea, and it can only be done with package variables, not lexically scoped variables (and lexically scoped variables are preferred to package variables -- see this answer来简单比较两者。
#!/usr/bin/env perl
use strict;
use warnings;
use 5.014;
our($foo1) = 1;
our($bar1) = undef;
our($baz1) = 3;
foreach my $name (qw(foo1 bar1 baz1)) {
{
no strict 'refs';
my($value) = $$name;
warn "$name: is not defined" unless defined $value;
say "$name: <$value>";
}
}
出于说明目的,使用 warn
而不是 die
。
</tmp> $ ./test.pl
foo1: <1>
bar1: is not defined at ./test.pl line 16.
Use of uninitialized value $value in concatenation (.) or string at ./test.pl line 17.
bar1: <>
baz1: <3>
您也可以使用通用代码循环遍历所有变量来检查它们:
#!/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>";
}
给出类似的输出:
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>";
}
我把 sort
放在那里是因为我喜欢确定性行为...
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>
如果测试真的像die if ! defined
那么简单,那么我可能会把它们列出来:
#!/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)个检查列表,那么我会看一下设计。
另请参阅此 PadWalker 代码示例,了解第一个选项的非常复杂的版本,但允许词法范围的变量。
今天看到这段代码:
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...? 还需要全部过一遍,逐个手动测试?
有没有更短、更“神奇”的方法来判断哪个变量未定义?
您可以创建一个 table 来稍微简化一下:
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";
}
}
可以用字符串求值来完成:
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;
}
你可以随心所欲地使用symbolic references, though using them is generally not a great idea, and it can only be done with package variables, not lexically scoped variables (and lexically scoped variables are preferred to package variables -- see this answer来简单比较两者。
#!/usr/bin/env perl
use strict;
use warnings;
use 5.014;
our($foo1) = 1;
our($bar1) = undef;
our($baz1) = 3;
foreach my $name (qw(foo1 bar1 baz1)) {
{
no strict 'refs';
my($value) = $$name;
warn "$name: is not defined" unless defined $value;
say "$name: <$value>";
}
}
出于说明目的,使用 warn
而不是 die
。
</tmp> $ ./test.pl
foo1: <1>
bar1: is not defined at ./test.pl line 16.
Use of uninitialized value $value in concatenation (.) or string at ./test.pl line 17.
bar1: <>
baz1: <3>
您也可以使用通用代码循环遍历所有变量来检查它们:
#!/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>";
}
给出类似的输出:
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>";
}
我把 sort
放在那里是因为我喜欢确定性行为...
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>
如果测试真的像die if ! defined
那么简单,那么我可能会把它们列出来:
#!/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)个检查列表,那么我会看一下设计。
另请参阅此 PadWalker 代码示例,了解第一个选项的非常复杂的版本,但允许词法范围的变量。