2

当我输入以下代码并运行它时,它会输入<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();
4

3 回答 3

3

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

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

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

于 2012-08-24T11:22:40.767 回答
2

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

可以将for my $x其视为每次通过循环创建一个新变量。内部子程序捕获此变量,而不是类似名称的包变量,其值永远不会从foo.

当您删除 时my,只会创建一个变量(一个包变量),因此在循环中创建的每个 sub 都引用同一个变量(其值从footoredblueto ... to violetto foo)。

于 2012-08-24T11:44:57.063 回答
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;在您的程序中执行变量的初始化。

于 2012-08-24T11:29:47.317 回答