为什么我要使用 Perl 匿名子程序而不是命名子程序?

问题描述:

我只是好奇为什么人们会选择在 Perl 中使用匿名子例程而不是命名子例程.谢谢.

I'm just curious why one would choose to use an anonymous subroutine, versus a named one, in Perl. Thanks.

  • 您可以将匿名子项存储在数组、散列和标量中.
  • 您可以在运行时构建它们
  • 您可以将它们作为参数传递给其他函数.
  • 您可以将变量保留在周围的范围内.
  • 最后一点可能是最重要的,因为它通常是 Perl 中命名与匿名子例程最意想不到的方面.示例:

    The last point is probably the most important, because it's often the most unexpected facet of named vs. anonymous subroutines in Perl. Example:

sub outer
{
  my $a = 123;

  sub inner
  {
    print $a, "
";
  }

  # At this point, $a is 123, so this call should always print 123, right?
  inner();

  $a = 456;
}

outer(); # prints 123
outer(); # prints 456! Surprise!

但是将内部"从命名子例程更改为对匿名子例程的引用并且它的工作方式并不那么令人惊讶:

But change "inner" from a named subroutine to a reference to an anonymous subroutine and it works is a much less surprising manner:

sub outer
{
  my $a = 123;

  my $inner = sub
  {
    print $a, "
";
  };

  # At this point, $a is 123, and since the anonymous subrotine 
  # whose reference is stored in $inner closes over $a in the 
  # "expected" way...
  $inner->();

  $a = 456;
}

# ...we see the "expected" results
outer(); # prints 123
outer(); # prints 123

(当然,每个人的期望都不同,因此预期"周围的恐吓引号".)

(Of course, everyone's expectations are different, thus the "scare quotes" around "expected.")

这是一个在实际代码中使用的示例(尽管应该注意 File::Find 接口通常被认为是一个糟糕的接口——因为它使用了全局变量,而不是它的使用匿名子程序):

Here's an example use in real code (though it should be noted that the File::Find interface is generally considered to be a poor one—due to its use of global variables, not its use of anonymous subroutines):

sub find_files
{
  my @files;

  my $wanted = sub
  { 
    if($something)
    {
      push @files, $File::Find::name;
    }
  };

  # The find() function called here is imported from File::Find
  find({ wanted => $wanted }, $directory);

  return @files;
}

将命名子例程作为 wanted 参数的值传递将需要使用只能使用一次的例程污染命名空间,并在定义一个命名子例程find_files() 子例程会表现出之前演示的意外"行为.

Passing a named subroutine as the value of the wanted parameter would require polluting the namespace with a routine that may only be used once, and defining a named subroutine within the find_files() subroutine would exhibit the "unexpected" behavior demonstrated earlier.