FATAL 未初始化警告 - 远距离操作
FATAL uninitialized warnings - action at a distance
我最近遇到了一个错误,当时 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 本身的错误。
这不是错误。您正在体验 side-effect 一项功能,该功能可防止对传递给 subs 的散列元素进行不必要的自动验证。
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]
被访问,此时它知道该元素是否需要被激活。这就是警告来自子程序的原因。
具体来说,当您调用 f($h{x})
时,Perl 不会将 $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
我最近遇到了一个错误,当时 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 本身的错误。
这不是错误。您正在体验 side-effect 一项功能,该功能可防止对传递给 subs 的散列元素进行不必要的自动验证。
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]
被访问,此时它知道该元素是否需要被激活。这就是警告来自子程序的原因。
具体来说,当您调用 f($h{x})
时,Perl 不会将 $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