启用警告后,perl 通常会打印Use of uninitialized value $foo
if$foo
在表达式中使用并且没有被赋值,但在某些情况下它是可以的,并且变量被视为false、0
或''
没有警告。
在哪些情况下可以在没有警告的情况下使用未初始化/未定义的变量?
根据perlsyn 文档,
在布尔上下文中,数字
0
、字符串'0'
和''
、空列表()
和undef
都是假的。所有其他值都为真。
因为未定义的值为false,所以下面的程序
#! /usr/bin/perl
use warnings;
my $var;
print "A\n" if $var;
$var && print "B\n";
$var and print "C\n";
print "D\n" if !$var;
print "E\n" if not $var;
$var or print "F\n";
$var || print "G\n";
D
通过输出G
没有警告。
如果您的代码将至少增加或减少一次标量,则无需将标量显式初始化为零:
#! /usr/bin/perl
use warnings;
my $i;
++$i while "aaba" =~ /a/g;
print $i, "\n";
上面的代码输出3
没有警告。
与隐式零类似,如果您至少附加一次,则无需将标量显式初始化为空字符串:
#! /usr/bin/perl
use warnings;
use strict;
my $str;
for (<*>) {
$str .= substr $_, 0, 1;
}
print $str, "\n";
一个例子是“自动复活”。来自维基百科的文章:
Autovivification 是 Perl 编程语言的一个显着特征,它涉及数据结构的动态创建。自动激活是在取消引用未定义的值时自动创建变量引用。换句话说,Perl 自动激活允许程序员引用结构化变量和该结构化变量的任意子元素,而无需事先明确声明变量的存在及其完整结构。
例如:
#! /usr/bin/perl
use warnings;
my %foo;
++$foo{bar}{baz}{quux};
use Data::Dumper;
$Data::Dumper::Indent = 1;
print Dumper \%foo;
即使我们没有显式初始化中间键,Perl 也会负责脚手架:
$VAR1 = { '酒吧' => { '巴兹' => { 'quux' => '1' } } };
如果没有自动生存,代码将需要更多样板:
my %foo;
$foo{bar} = {};
$foo{bar}{baz} = {};
++$foo{bar}{baz}{quux}; # finally!
不要将自动生存与它可能产生的未定义值混淆。例如与
#! /usr/bin/perl
use warnings;
my %foo;
print $foo{bar}{baz}{quux}, "\n";
use Data::Dumper;
$Data::Dumper::Indent = 1;
print Dumper \%foo;
我们得到
在 ./prog.pl 第 6 行的打印中使用未初始化的值。 $VAR1 = { '酒吧' => { '巴兹' => {} } };
请注意,中间键自动激活。
自动复活的其他例子:
引用数组
my $a;
push @$a => "foo";
对标量的引用
my $s;
++$$s;
参考哈希
my $h;
$h->{foo} = "bar";
遗憾的是,Perl (还没有!)自动激活以下内容:
my $code;
$code->("Do what I need please!");
在回答类似问题时,ysth 报道
某些运算符为了您的方便而故意忽略“未初始化”警告,因为它们通常用于左侧或唯一操作数的默认值 0 或“”有意义的情况。
它们是:
++
和(前--
或后)+=
,,,,,,,,,,。-=
.=
|=
^=
&&=
||=
作为“定义或”,//=
很高兴地在没有警告的情况下改变一个未定义的值。
始终修复警告,即使是讨厌的恼人的警告。
可以关闭未定义的警告。您可以通过为操作创建新范围来做到这一点。有关perldoc perllexwarn
更多信息,请参阅。此方法适用于所有版本的 perl。
{
no warnings 'uninitialized';
my $foo = "foo" + undef = "bar";
}
对于很多二元运算符,您可以使用新的 Perl 5.10 东西,~~
并且//
; 有关perldoc perlop
更多信息,请参阅。
use warnings;
my $foo = undef;
my $bar = $foo // ''; ## same as $bar = defined $foo ? $foo : ''
//=
如果变量未定义,也是设置变量的变体:
$foo //= '';
Smart Matching ( ~~
) 运算符很酷,并且允许进行智能比较,这很不错,请查看perldoc perlsyn
:
use warnings;
my $foo = "string";
say $foo eq undef; # triggers warnings
say $foo ~~ undef; # no undef warnings
真正的答案应该是:为什么要打开该警告?undef 是一个非常好的变量值(任何使用过数据库的人都可以告诉你),区分真(发生了某事)、假(什么都没发生)和 undef(发生了错误)通常是有意义的。
而不是说
use strict;
use warnings;
说
use common::sense;
并且您将获得警告的所有好处,但会关闭未定义变量等烦人的警告。
common::sense 可从 CPAN 获得。