【问题标题】:What is meant by proper closure here这里的适当关闭是什么意思
【发布时间】:2012-08-21 15:16:58
【问题描述】:

这是直接取自 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 会使用词法变量?

【问题讨论】:

    标签: perl closures subroutine lexical typeglob


    【解决方案1】:

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

    “typeglobs cannot be defined for lexical variables”这句话误解了关于 typeglobs 的几个关键点。您将其读作“您不能使用 '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”

    【讨论】:

    • 谢谢。你能解释一下为什么块中的第二个print &amp;$global_sub() 会打印出red,即使$global_sub 持有对名称为redsub 的引用并且这个sub 刚刚被在块内本地重新定义?
    • @Cupidvogel $global_sub 持有代码参考。这是对编译代码的引用,而不是对子例程名称的引用。它是通过按名称引用子例程来创建的,但是一旦存储了引用,该引用就不再由该名称定义。使用它的行不按名称调用它,它使用对代码本身的引用来调用它。我在使用符号(按名称)和硬(CODE)引用的地方添加了说明。希望这会有所帮助。
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      来自perlfaq7

      What's a closure?

      闭包记录在perlref

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

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

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

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

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

      1/ 正确关闭是什么意思? - 见上文

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

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

      这是否更有帮助?

      【讨论】:

      • 这很有帮助,但不是我正在寻找的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-15
      • 1970-01-01
      • 2017-07-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多