对于Loop和Lexically Scoped变量

Dav*_* W. 4 perl

版本#1

use warnings;
use strict;

my $count = 4;

for $count (1..8) {
    print "Count = $count\n";
    last if ($count == 6);
}

if (not defined($count)) {
    print "Count not defined\n";
}
else {
    print "Count = $count\n";
}
Run Code Online (Sandbox Code Playgroud)

这打印:

1
2
3
4
5
6
4
Run Code Online (Sandbox Code Playgroud)

为什么?因为for循环$count在其块内创建了自己的词法范围版本.

版本#2

use warnings;
use strict;

my $count;
for $count (1..8) {
    print "Count = $count\n";
    last if ($count == 6);
}

if (not defined($count)) {
    print "Count not defined\n";
}
else {
    print "Count = $count\n";
}

1
2
3
4
5
6
Count not defined
Run Code Online (Sandbox Code Playgroud)

哎呦!我想捕获退出值$count,但for循环有它自己的词法范围版本$count!我只是花了两个小时试图追踪这个错误.

版本#3

use warnings;
use strict;

for $count (1..8) {
    print "Count = $count\n";
    last if ($count == 6);
}

print "That's all folks!\n";
Run Code Online (Sandbox Code Playgroud)

这给了我错误Global symbol "$count" requires explicit package name at line 5.但是,我认为$countfor块内自动词法范围.似乎只有在我已经在其他地方声明了这个变量的词法范围版本时才会发生这种情况.

这种行为的原因是什么?是的,我知道康威的决定了你应该总是使用myfor循环变量,但问题是为什么Perl的解释器设计成这样.

Eri*_*rom 8

在Perl中,循环中对变量的赋值始终本地化为循环,循环变量始终是循环值的别名(意味着您可以通过修改循环变量来更改原始元素).包变量(our)和词法变量(my)都是如此.

这种行为最接近于Perl对包变量的动态范围(使用local关键字),但也特别适用于词法变量(在循环中或在手之前声明).

在任何情况下,循环结束后循环变量中的循环值都不会存在.对于循环范围变量,这是相当直观的,但对于范围超出循环的变量,行为类似于local由循环创建的块范围内的(在)内部的值.

for our $val (1 .. 10) {...} 
Run Code Online (Sandbox Code Playgroud)

相当于:

our $val;
my @list = 1 .. 10;
my $i = 0;

while ($i < @list) {
   local *val = \$list[$i++];
   # loop body
}
Run Code Online (Sandbox Code Playgroud)

在纯perl中,不可能编写扩展的词法版本,但如果使用类似的模块Data::Alias:

my $val;
my @list = 1 .. 10;
my $i = 0;

while ($i < @list) {
   alias $val = $list[$i++];
   # loop body
}
Run Code Online (Sandbox Code Playgroud)


mob*_*mob 5

实际上,在版本#3中,变量是"本地化的"而不是词法范围.

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

在任何情况下,您都无法从for循环外的-loop的stlye 访问循环变量.但你可以使用其他风格(C风格)for-loop:

my $count;
for ($count=1; $count <= 8; $count++) {
    last if $count == 6;
}
...   # $count is now 6.
Run Code Online (Sandbox Code Playgroud)