#!/usr/bin/env perl
use strict;
use warnings FATAL => qw ( all );
my ( $func, @list, $num );
$func = sub {
print $num // "undef"; print "\n";
};
@list = ( 1,2,3 );
foreach $num ( @list ) {
$func->();
};
这件perl打印
undef
undef
undef
而不是
1
2
3
$func
例程可以看到@list
,为什么不$num
?
答案 0 :(得分:4)
因为foreach
循环隐式地本地化它们的迭代器变量。
请参阅:perlsyn
foreach循环遍历正常列表值并依次将变量VAR设置为列表的每个元素。如果变量前面带有关键字my,则它是词法范围的,因此仅在循环中可见。否则,该变量隐含在循环的本地,并在退出循环时重新获得其前一个值。如果先前使用my声明了变量,则它使用该变量而不是全局变量,但它仍然本地化为循环。这种隐式定位仅在foreach循环中发生。
但实际上 - 这并不经常出现,因为从外部做任何类型的循环迭代器都是非常糟糕的形式。缩小范围,并传递变量以避免错误和故障排除。
答案 1 :(得分:1)
您正在访问$num
变量的本地化版本,如Sobrique所说。您的意图是使用对变量$num
的引用。这就是我在这里展示的内容:
my ( $func, @list, $num );
$func = sub {
print $$num // "undef"; print "\n";
};
@list = ( 1,2,3 );
foreach ( @list ) {
$num = \$_;
$func->();
};
您还可以使用变量的全局版本,而不是词汇:
my ( $func, @list, $num );
$func = sub {
print $main::num // "undef"; print "\n";
};
@list = ( 1,2,3 );
foreach $main::num ( @list ) {
$func->();
};
但这是一种愚蠢的方式来封装它。您不应该在子例程中使用全局变量。这不是好习惯。相反,将值传递给sub并通过@_
变量(在本例中为第一个数组索引$_[0]
)访问它:
my $func = sub {
print $_[0] // "undef"; print "\n";
};
my @list = ( 1,2,3 );
for ( @list ) {
$func->($_);
};
我还修改了上面的一些惯用编码风格。
答案 2 :(得分:0)
嗯,从文档中猜出原因是这样的:
foreach循环遍历正常列表值并设置 变量VAR依次是列表的每个元素。如果变量 之前是关键字my,然后它是词法范围的,并且是 因此仅在循环内可见。否则,变量是 隐含地循环本地并在退出时重新获得其原值 循环。如果先前使用my声明了变量,则使用 该变量而不是全局变量,但它仍然是本地化的 循环。这种隐式定位仅在foreach循环中发生。
这意味着我不应该使用foreach循环,但是为了或者同时...
答案 3 :(得分:0)
我可以引用perlsyn,但perlsyn似乎并没有说清楚是什么情况。变量不是“本地化的”,并且在退出循环时没有任何东西“重新获得”它的值。声明循环变量时外部变量隐藏,并且在循环之后可见。
隐式隐藏外部作用域中的变量,保留其值。
此代码剪贴簿的输出将说明:
use 5.022;
use strict;
use warnings FATAL => qw ( all );
use Data::Dumper;
my ( $func, @list, $num );
$func = sub {
print $num // "undef"; print "\n";
};
$num = 101;
$func->();
my $np = \$num;
print Data::Dumper->Dump( [ $np ], [ '*np' ] );
@list = ( 1,2,3 );
foreach $num ( @list ) {
print Data::Dumper->Dump( [ $num ], [ '*num' ] );
print Data::Dumper->Dump( [ $np ], [ '*np' ] );
my $np2 = \$num;
print Data::Dumper->Dump( [ $np2 ], [ '*np2' ] );
print Data::Dumper->Dump( [ $np ], [ '*np' ] );
$$np++;
$func->();
}
哪个输出:
101
$np = \101;
$num = 1;
$np = \101;
$np2 = \1;
$np = \101;
102
$num = 2;
$np = \102;
$np2 = \2;
$np = \102;
103
$num = 3;
$np = \103;
$np2 = \3;
$np = \103;
104
因此,在循环内部,符号$num
根本不会引用$np
指向的内存,而是引用$np2
指向的内存。