可能对未定义的取消引用数组进行迭代是错误还是功能?

Is possible iteration over undefined dereferenced array a bug or a feature?

以下代码按预期崩溃,因为 $x 不包含数组引用:

$ perl -E 'use strict; use warnings; my $x; say @{$x}; say "OK";'

Can't use an undefined value as an ARRAY reference at -e line 1.

然而这段代码在没有任何警告的情况下运行:

perl -E 'use strict; use warnings; my $x; say for @{$x}; say "OK";'

OK

为什么?我没有在 perldoc 中找到任何关于此行为的文档。 看起来 for 上下文在这里暗示了一些 DWIM-ness 逻辑(具有危险的后果)。

希望这有点启发:

$ perl -E 'use strict; use warnings; my $x; say for @{$x}; say $x;'
ARRAY(0x561b92479420)

$x 变量正在由 for 自动生成。

比较:

$ perl -E 'use strict; use warnings; my $x; $x->[0]; say $x;'
Useless use of array element in void context at -e line 1.
ARRAY(0x561b92479420)

对未定义标量的某些引用操作将导致自动生成发生。 for @{$var} 显然是其中之一。 CPAN 上有一个 autovivication 模块,可让您更好地控制自动激活发生的时间。

你有这个声明:

say for @{$x}

$x 的值是 undef,所以当你解引用它时,Perl 注意到你想使用 $x 作为数组引用。然后它会为您创建数组(“autovivification”)。该数组为空,因此 for 无法迭代任何内容。

Autovivification 是使我们能够在此循环中执行计数等任务的功能。当 $first 的键不存在时,Perl 将该键添加到散列中。但是,需要有一个二级散列,其中 $second 可以是一个键。由于 $first 键的值为 undef,Perl 自动生成二级散列,因此您可以对其进行操作:

for ( ... ) {
    # source.example.com dest.example.org 1234
    my( $first, $second, $count ) = split;
    $hash->{$first}{$second} += $count;
    }

想象一下,如果您必须提前知道所有键、哈希大小等,或者必须自己扩展或修改数据结构大小,那么这项任务会有多困难。

我们在 Intermediate Perl, the book in the tutorial series where we talk about references. I also write about it in Understand autovivification 中有一个扩展示例。

@tobyink 提到了 autovificiation pragma。它识别某些构造并可以警告或停止您的程序:

use v5.10;
use warnings;

no autovivification qw(store);

my $x;
for ( @$x ) {
    say "Got value: $_";
    }

say "End. x = $x";

现在程序停止:

Can't vivify reference at ...

但是,所有这些都会让您的程序变慢一些,因为 Perl 必须做额外的工作来检查所有这些。

还有 Whosebug 答案 How do I disable autovivification in Perl?,但我认为这些答案没那么有用。

您应该习惯于自动生成和在它存在的环境中进行编程(以及您可能不小心做的所有其他事情来产生错误)。