不本地化循环变量会产生不同的结果

时间:2012-08-24 11:11:06

标签: perl closures

当我输入以下代码并运行它时,它会输入< FONT COLOR ='foo'>< / FONT> 。但是,当我将my添加到循环变量(for my $name (@colors))时,它会输入预期的< FONT COLOR ='red'>< / FONT> 。任何人都可以解释原因吗?

@colors = qw(red blue green yellow orange purple violet);
$name = 'foo';
for $name (@colors) {
  no strict 'refs';
  *$name = sub { "<FONT COLOR='$name'></FONT>" };
}
print red();

3 个答案:

答案 0 :(得分:3)

在你的循环中你创建了几个潜艇。这些子可以看到它们在其中创建的上下文的所有变量。

如果我们使用局部/全局变量,则sub将始终看到最新值(变量插入字符串不会在编译时或“定义时间”发生,但是当执行sub时。 )在我们的例子中,循环的当前值 foo

如果我们使用my的词法变量,我们在循环中使用的变量在循环外部是不可见的,在循环的所有其他迭代中是不可见的。然而,它本身仍然可见。这称为闭包。闭包仅适用于词法变量,是实现信息隐藏或构建专门定制的子类的强大方法,如示例代码中所示。

答案 1 :(得分:2)

闭包捕获变量,而不是值。

for my $x视为每次循环创建一个新变量。内部子捕获此变量而不是类似命名的包变量,其值永远不会从foo更改。

当你删除my时,只创建了一个变量(一个包变量),所以在循环中创建的每个sub都会转换为同一个变量(其值从foo变为{{1 } red到... blueviolet)。

答案 2 :(得分:1)

for循环中使用的变量附加了一些魔法。对于循环的每次迭代,将其设置为适当的值。在循环结束后,$ name被设置为它的旧值。基本上,您创建的每个子组都会看到相同的变量,从而更改其值。我修改了你的例子来证明这一点:

@colors = qw(red blue green yellow orange purple violet);
$name = 'foo';
for $name (@colors) {
  no strict 'refs';
  *$name = sub { "<FONT COLOR='$name'></FONT>" };
  print $name . &{$name} . "\n";
}
print red() . "\n";

您可以使用函数my来定义局部变量,如下所示:

for my $name (@colors) {

根据经验,您应该始终在程序中use strict;,这会强制执行变量的初始化。