当use warnings FATAL ...
pragma将来自其他地方的静音警告解释为死亡原因时,我最近遇到了一个错误。请考虑以下示例:
use strict;
# In one file:
no warnings;
my %hash;
Foo->bar( my $temp = $hash{ +undef } ); # this lives
Foo->bar( $hash{ +undef } ); # this dies
# Elsewhere
package Foo;
use warnings FATAL => qw(uninitialized);
sub bar {
my ($self, $param) = @_; # prefectly safe
$param = "(undef)"
unless defined $param; # even safer
print "Param: $param\n";
}
现在,这当然可以使用与整个项目中的警告相同的策略来固定大部分时间。或者这可以在每次发生时通过排除特定位置的undefs来修复(参见# this lives
行)。
我的问题是对于包Foo是否有一个可接受的解决方案,它不需要更改调用它的任何东西,以及这是否真的是Perl本身的错误。
答案 0 :(得分:2)
这不是一个错误。您遇到了一个功能的副作用,该功能可以防止对传递给子网站的哈希元素进行不必要的自动修改。
Perl通过引用传递。这意味着对函数中参数的更改将改变外部参数。
$ perl -E'
sub f { $_[0] = "xyz"; }
f($x);
say $x;
'
xyz
这也适用于哈希元素。
$ perl -E'
sub f { $_[0] = "xyz"; }
my %h;
f($h{x});
say $h{x};
'
xyz
sub并不知道有关散列的任何信息,因此必须在输入sub之前创建散列元素,以便有一些东西要分配。
......或者是吗?如果元素不存在,f($h{x})
总是不希望创建$h{x}
。因此,Perl推迟进行哈希查找,直到访问$_[0]
为止,此时它已知道该元素是否需要被激活。这就是警告来自潜艇的原因。
具体来说,当您拨打$h{x}
时,Perl不会将f($h{x})
传递给子。相反,它传递一个神奇的标量,其中包含对%h
的引用和键值(x
)。这推迟了哈希查找,直到访问$_[0]
,其中已知$_[0]
是否可在可分配的地方使用。
如果以不改变的方式使用$_[0]
(即,如果它被用作右值),则查找哈希元素而不对其进行操作。
如果$_[0]
以可以更改的方式使用(即,如果它被用作左值),则哈希元素将被生效并返回。
$ perl -E'
sub f { my $x = $_[0]; } # $_[0] returns undef without vivifying $h{x}
sub g { $_[0] = "xyz"; } # $_[0] vivifies and returns $h{x}
my %h;
f($h{x});
say 0+keys(%h);
g($h{x});
say 0+keys(%h);
'
0
1