致命的未初始化警告 - 远距离行动

时间:2016-01-13 18:02:01

标签: perl warnings

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本身的错误。

1 个答案:

答案 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