Perl中foreach循环的默认范围是什么?

时间:2010-02-10 16:43:53

标签: perl foreach scope

在Perl中,在foreach循环中使用'my'会产生什么影响吗?无论是否使用'my',索引变量似乎始终是本地的。那么你可以在foreach循环中删除'my'并且仍然在循环体内有私有范围吗?

可以看出,使用'for'循环使用/不使用'my'之间存在差异:

use strict; 
use warnings; 

my ($x, $y) = ('INIT', 'INIT'); 

my $temp = 0; 

for ($x = 1; $x < 10; $x++) {
 $temp = $x+1; 
}

print "This is x: $x\n";   # prints 'This is x: 10'. 

for (my $y = 1; $y < 10; $y++) {
 $temp = $y+1; 
}

print "This is y: $y\n";   # prints 'This is y: INIT'. 

但是对于foreach它似乎没有效果:

my ($i, $j) = ('INIT', 'INIT'); 

foreach $i (1..10){
    $temp = $i+1;
}

print "\nThis is i: $i\n";   # prints 'This is i: INIT'. 



foreach my $j (1..10){
    $temp = $j+1;
}

print "\nThis is j: $j\n";   # prints 'This is j: INIT'. 

5 个答案:

答案 0 :(得分:14)

来自http://perldoc.perl.org/perlsyn.html#Foreach-Loops

  

foreach循环遍历正常列表值并依次将变量VAR设置为列表的每个元素。如果变量前面带有关键字my,则它是词法范围的,因此仅在循环中可见。否则,该变量隐含在循环的本地,并在退出循环时重新获得其前一个值。如果先前使用my声明了变量,它将使用该变量而不是全局变量,但它仍然本地化为循环。这种隐式定位仅在foreach循环中发生。

答案 1 :(得分:11)

Hans链接到描述foreach循环中的变量如何作用域的文档。区别是微妙的,但它可能很重要:

sub f { return $i }
$i = 4;
$m = $n = 0;

foreach    $i (1 .. 10) { $m += f() }
foreach my $i (1 .. 10) { $n += f() }

print "Result with localization:    $m\n";    #  ==>  55
print "Result with lexical scoping: $n\n";    #  ==>  40

答案 2 :(得分:1)

关于Perl我发现的最痛苦的发现之一是foreach循环上的“my”变量不是本地副本。我发现自己很沮丧地发现我的阵列被摧毁了。

唯一的方法似乎是:


foreach ( @array ) {
  my $element = $_; # make a local copy
  ...
}

如果查看perldoc,它会说:“foreach循环索引变量是列表中您循环的每个项目的隐式别名”和“如果LIST的任何元素是左值,那么可以通过修改循环中的VAR来修改它。“

答案 3 :(得分:0)

我刚刚对这个有趣的问题做了一些额外的研究。

如果你做“我的$ y”,foreach并不在乎。在循环之前。迭代器仍将仅在范围内更改:

my $y;
foreach $y (1..10) {}

$ y会在foreach范围内发生变化,但当它离开时,它会恢复到循环之前的状态。

我原以为或许foreach会自动执行“我的$ y”;在它开始运行之前,所以我尝试了严格的模式,但是这个解释没有削减它,因为它仍然要求:

foreach my $y (1..10) {}

而不是:

foreach $y (1..10) {}

......如果“foreach $ y”在功能上与“foreach my $ y”相同,则认为没有必要。

答案 4 :(得分:0)

foreach循环中的迭代器实际上是循环的本地。也就是说,它直接保存列表中的值,实际上是通过引用调用而不是按值。因此,如果在循环中操作值,它将更改列表中的值。但是,迭代器变量仅在引用循环时定义:

@names = qw(Kirk Spock Bones);

$officer = "Riker";
print "@names $officer\n"; # will print Kirk Spock Bones Riker

foreach $officer (@names) {
     $officer .= "y";
}

print "@names $officer\n"; # will print Kirky Spocky Bonesy Riker

因此,迭代器(在本例中为$ officer)在保留foreach循环之前的任何值方面有效地以'my'开头。但是,如果更改的值已更改,则更改将传递回您正在迭代的列表。