U. *_*ndl 2 perl closures subroutine
Perl 5.18.2 accepts "local subroutines", it seems.
Example:
sub outer()
{
my $x = 'x'; # just to make a simple example
sub inner($)
{
print "${x}$_[0]\n";
}
inner('foo');
}
Run Code Online (Sandbox Code Playgroud)
Without "local subroutines" I would have written:
#...
my $inner = sub ($) {
print "${x}$_[0]\n";
}
$inner->('foo');
#...
Run Code Online (Sandbox Code Playgroud)
And most importantly I would consider both to be equivalent.
However the first variant does not work as Perl complains:
Variable $x is not available at ...
where ... describes the line there $x is referenced in the "local subroutine".
Who can explain this; are Perl's local subroutines fundamentally different from Pascal's local subroutines?
问题中的术语“局部子例程”似乎指的是词汇子例程。这些是私有子例程,仅在定义它们的范围(块)内可见,在定义之后;就像私有变量一样。
\nmy但它们是用or定义(或预先声明)的state,如my sub subname { ... }
仅仅编写sub subname { ... }另一个子例程的内部不会使其成为“本地”(在 Perl 的任何版本中),但它的编译就像与其他子例程一起编写一样,并放置在其包的符号表中(main::例如例子)。
该问题在标题中提到了关闭,这是对此的评论
\nPerl 中的闭包是程序中的一个结构,通常是一个标量变量,带有对 sub 的引用,并且在其(运行时)创建时从其范围携带环境(变量)。另请参阅perlfaq7 条目。解释起来很乱。例如:
\nsub gen { \n my $args = "@_"; \n\n my $cr = sub { say "Closed over: |$args|. Args for this sub: @_" }\n return $cr;\n}\n\nmy $f = gen( qw(args for gen) );\n\n$f->("hi closed");\n# Prints:\n# Closed over: |args for gen|. Args for this sub: hi closed\nRun Code Online (Sandbox Code Playgroud)\n匿名子“关闭”其定义范围内的变量,从某种意义上说,当其生成函数返回其引用并超出范围时,由于该引用的存在,这些变量仍然存在。\n因为匿名 sub 是在运行时创建的,每次调用其生成函数并重新创建其中的词法时,anon sub 也是如此,因此它始终可以访问当前值。\n因此,返回的对 anon-sub 的引用使用词法数据,这将否则就消失了。一点点魔法。\xe2\x80\xa0
\n回到“本地”潜艇的问题。如果我们想引入问题的实际闭包,我们需要从outer子例程返回一个代码引用,例如
sub outer {\n my $x = \'x\' . "@_";\n return sub { say "$x @_" }\n}\nmy $f = outer("args");\n$f->( qw(code ref) ); # prints: xargs code ref\nRun Code Online (Sandbox Code Playgroud)\n或者,根据主要问题,如v5.18.0 和v5.26.0中引入的稳定版本,我们可以使用命名的词法(真正嵌套!)子例程
\nsub outer {\n my $x = \'x\' . "@_";\n \n my sub inner { say "$x @_" };\n\n return \\&inner;\n}\nRun Code Online (Sandbox Code Playgroud)\n在这两种情况下,都会返回正确使用局部词法变量 ( ) 及其最新值的my $f = outer(...);代码引用。outer$x
outer但是我们不能在闭包中使用普通的命名 sub
sub outer {\n ...\n\n sub inner { ... } # misleading, likely misguided and buggy\n\n return \\&inner; # won\'t work correctly\n}\nRun Code Online (Sandbox Code Playgroud)\n这inner是在编译时创建的并且是全局的,因此它使用的任何变量都将在第一次调用outer时烘焙它们的值。outer因此只有在下次调用之前inner才是正确的——当 中的词法环境被重新创建但没有重新创建时。作为一个例子,我可以很容易地找到这篇文章,并查看perldiag 中的条目(或添加到程序中)。outerouterinneruse diagnostics;
\xe2\x80\xa0在我看来,在某种程度上,这是一个穷人的对象,因为它具有功能和数据,是在其他时间在其他地方制作的,并且可以与传递给它的数据一起使用(并且两者都可以更新) )
\n