可能对未定义的取消引用数组进行迭代是错误还是功能?
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?,但我认为这些答案没那么有用。
您应该习惯于自动生成和在它存在的环境中进行编程(以及您可能不小心做的所有其他事情来产生错误)。
以下代码按预期崩溃,因为 $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?,但我认为这些答案没那么有用。
您应该习惯于自动生成和在它存在的环境中进行编程(以及您可能不小心做的所有其他事情来产生错误)。