8

这是一些简单的 Perl 来计算一个值在数组中出现的次数。这运行没有任何警告。

use warnings;
use strict;

my @data = qw(1 1 2 3 4 5 5 5 9);
my %histogram;
foreach (@data)
{
    $histogram{$_}++;
}

当循环体更改为

$histogram{$_} = $histogram{$_} + 1;

Perl 警告“另外使用未初始化的值”。

引擎盖下发生了什么?为什么将值作为操作数提供给 ++ 运算符并使用 + 运算符未初始化时进行初始化?

4

4 回答 4

15

+ 运算符计算左边的形式和右边的形式,然后返回两者的总和。哈希调用评估没有看到任何特殊的上下文。

++ 运算符内置了一些特殊的魔法。引用 perlop 联机帮助页,关于 ++ 运算符:

“undef”始终被视为数字,特别是在递增之前更改为 0(因此 undef 值的后递增将返回 0 而不是“undef”)。

编辑:为了详细说明差异, ++ 更改了适当的值,而 + 只是将其参数作为输入。当 + 看到未定义的值时,通常会出现问题,但对于 ++,您的哈希操作示例非常典型——用户希望将 undef 视为 0,而不是每次都检查和初始化。因此,以这种方式对待这些运算符似乎是有意义的。

于 2008-11-04T03:05:05.047 回答
8

不是 Perl 必须初始化值,而是它并不总是警告它们。不要试图为此考虑一个规则,因为你总是会发现异常,而且当你认为你已经弄清楚时,下一个版本的 Perl 会改变你的警告。

在这种情况下,正如 Harleqin 所说,自增运算符有一个特殊情况。

于 2008-11-04T03:22:02.390 回答
8

某些运算符为了您的方便而故意忽略“未初始化”警告,因为它们通常用于左侧或唯一操作数的默认值 0 或“”有意义的情况。

它们是:++ 和 --(前或后)、+=、-=、.=、|=、^=、&&=、||=。

请注意,其中一些在绑定变量上使用时会错误地发出警告:请参阅http://perl5.git.perl.org/perl.git/blob/HEAD:/t/op/assignwarn.t中标记为 TODO 的测试.

于 2008-11-04T04:52:55.170 回答
0

正如布赖恩所说:它仍然会这样做,它只是警告你。警告会告诉您某些操作可能会产生您意想不到的效果。

您特别要求的值$histogram{$_},向其添加 1,然后将其分配给同一个插槽。这与我不希望自动生存在这里工作的方式相同:

my $hash_ref = $hash_for{$key_level_1};
$hash_ref->{$key_level_2} = $value;

就像这里一样:

$hash_for{$key_level_1}{$key_level_2} = $value;

魔术可能不像优化那样起作用。优化编译器会注意到这与汇编语言中有一个增量运算符是a = a + 1一样a++的,它可以使用该优化指令而不是假装它需要保留第一个值,然后覆盖它,因为它不是实际需要。

优化是一次额外的审查和开销,以提高每次运行的性能。但是在动态语言中不能保证您不会以与您试图减少它的速度相同的速度增加开销。

于 2008-11-04T04:14:25.577 回答