6

这是直接从Perl Cookbook中提取的代码:

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

其目的是形成 6 个不同颜色的子程序。在解释部分,书中写道:

这些函数看起来都是独立的,但真正的代码实际上只编译了一次。这种技术节省了编译时间和内存使用。要创建正确的闭包,匿名子例程中的任何变量都必须是词法。这就是循环迭代变量上 my 的原因。

适当的闭包是什么意思,如果my省略了会发生什么?另外,即使不能为词法变量定义 typeglob 并且应该抛出错误,typeglob 怎么会与词法变量一起工作?

4

3 回答 3

7

正如其他人所提到的,食谱使用术语“适当的”来指代创建一个带有来自更高词法范围的变量的子例程的事实,并且该变量不再可以通过任何其他方式访问。我使用过度简化的助记符“对$color变量的访问是'关闭'”来记住这部分闭包。

声明“不能为词法变量定义类型团”误解了关于类型团的几个关键点。您将其读作“您不能使用 'my' 来创建 typeglob”,这在某种程度上是正确的。考虑以下:

my *red = sub { 'this is red' };

这将在“my *red”附近出现“语法错误”,因为它试图使用“my”关键字定义类型团。

但是,您示例中的代码并没有尝试这样做。它定义了一个全局的类型团,除非被覆盖。它使用词法变量的值来定义类型团的名称。

顺便说一句,typeglob 可以是词法本地的。考虑以下:

my $color = 'red';

# create sub with the name "main::$color". Specifically "main:red"
*$color = sub { $color };

# preserve the sub we just created by storing a hard reference to it.
my $global_sub = \&$color;

{
  # create a lexically local sub with the name "main::$color".
  # this overrides "main::red" until this block ends
  local *$color = sub { "local $color" };

  # use our local version via a symbolic reference.
  # perl uses the value of the variable to find a
  # subroutine by name ("red") and executes it
  print &$color(), "\n";

  # use the global version in this scope via hard reference.
  # perl executes the value of the variable which is a CODE
  # reference.
  print &$global_sub(), "\n";

  # at the end of this block "main::red" goes back to being what
  # it was before we overrode it.
}

# use the global version by symbolic reference
print &$color(), "\n";

这是合法的,输出将是

local red
red
red

在警告下,这将抱怨“Subroutine main::red redefined”

于 2012-08-21T16:09:37.490 回答
6

我相信“适当的关闭”实际上意味着关闭。如果 $name 不是词法,所有的 subs 将引用同一个变量(其值将被重置为它在 for 循环之前的任何值,如果有的话)。

*$name正在使用 $name 的值作为有趣的取消引用 * sigil 的引用。由于 $name 是一个字符串,它是一个符号引用(因此没有严格的 'refs')。

于 2012-08-21T15:56:54.233 回答
1

perlfaq7

什么是闭包?

闭包记录在perlref中。

闭包是一个计算机科学术语,具有精确但难以解释的含义。通常,闭包在 Perl 中作为匿名子例程实现,并在它们自己的范围之外持续引用词法变量。这些词法神奇地引用了定义子程序时周围的变量(深度绑定)。

闭包最常用于编程语言中,您可以让函数的返回值本身就是一个函数,就像在 Perl 中一样。请注意,某些语言提供匿名函数但不能提供适当的闭包:例如 Python 语言。有关闭包的更多信息,请查看任何有关函数式编程的教科书。Scheme 是一种不仅支持而且鼓励闭包的语言。

答案继续以相当详细的方式回答问题。

Perl 常见问题解答是一个很好的资源。但是,如果没有人阅读它们,那么维护它们就有点浪费了。

编辑(以更好地回答您帖子中的后续问题):

1/ 适当关闭是什么意思?- 看上面

2/ 如果省略 my 会发生什么?- 行不通。尝试一下,看看会发生什么。

3/ typeglob 怎么会使用词法变量?- 该变量$name仅用于定义要使用的 typeglob 的名称。它实际上并没有被用作 typeglob。

是不是更有帮助?

于 2012-08-21T15:28:31.657 回答