为什么 Perl 的 foreach 不要求用 my 声明变量?

问题描述 投票:0回答:2

今天,我在 Perl 中偶然发现了一些我不知道的东西:它“本地化”了列表中迭代的元素所分配的变量。

当然,Perl 文档中记录了这一点 - 但我没能记住或阅读它。

以下脚本演示了我的意思:

use warnings;
use strict;

my $g = 99;

foreach $g (1..5) {
  p($g);
}

sub p {
  my $l = shift;
  printf ("%2d %2d\n", $g, $l);
}

脚本打印

99  1
99  2
99  3
99  4
99  5

因为

$g
已“本地化”到
foreach
循环。

据我所知,如果我在 foreach 循环中将

my
添加到
$g
没有什么区别:

foreach my $g (1..5) {

实际上,我最终这样做是因为我觉得这样可以更清楚地表明该变量是循环的本地变量。

我现在的问题是:是否有一种情况,我的使用

my
确实会产生影响(假设
$g
已经在全球范围内声明)。

perl variables foreach local-variables
2个回答
8
投票

调查的行为记录在 perlsyn 中的 Foreach 循环

foreach
循环迭代普通列表值,并依次将标量变量 VAR 设置为列表的每个元素。如果变量前面带有关键字
my
,则它是词法作用域的,因此仅在循环内可见。

继续解释

否则,该变量隐式地位于循环本地,并在退出循环时恢复其先前的值。如果该变量之前使用

my
声明,则它使用该变量而不是全局变量,但它仍然本地化到循环。

因此,使用

my
进行本地化或将其留给
foreach
进行本地化应该没有区别。

有点好奇就是这样

这种隐式定位发生在

foreach
循环中。

所有这些都在来自 perlsub

Private Variables via my()

的这段代码中得到了进一步澄清

foreach
循环默认以
local
的方式动态确定其索引变量的范围。但是,如果索引变量以关键字
my
为前缀,或者作用域中已经存在该名称的词法,则会创建一个新的词法。

由于在这两种情况下都创建了新的词汇is,因此不会有任何实际差异。

我绝对支持并建议(总是)在那里有

my


0
投票

根据@zdim,这段代码:

use strict;    
my $g;    
foreach $g (1..5) {
  p($g);
}

在功能上等同于此代码:

use strict;    
my $g;    
foreach my $g (1..5) {
  p($g);
}

但请注意,此代码会产生错误:

use strict;    
foreach $g (1..5) {
  p($g);
}
my $g;    

要获得隐式声明,首先必须有显式声明。 这按设计实施。或者至少,这是按照文档实现的。对我来说,它仍然感觉像是一个错误。如果它不打算使用现有的声明,我更希望它抛出一个未定义的符号错误。

您可以使用

our
而不是
my
来防止此行为。

例如这段代码:

use strict;
our $g = 99;
foreach $g (1..5) {
  p($g);
}
printf ("%2d\n", $g);
sub p {
  my $l = shift;
  printf ("%2d %2d\n", $g, $l);
}

产生此输出:

 1  1
 2  2
 3  3
 4  4
 5  5
99

循环结束后

$g
仍恢复原来的值,但现在
$g
在循环内和循环外是同一个变量。

© www.soinside.com 2019 - 2024. All rights reserved.