封闭中的本地变量可见性与本地`
Perl 5.18.2似乎接受“本地子例程”。
示例:
sub outer()
{
my $x = 'x'; # just to make a simple example
sub inner($)
{
print "${x}$_[0]\n";
}
inner('foo');
}
如果没有“本地子例程”,我会写的:
#...
my $inner = sub ($) {
print "${x}$_[0]\n";
}
$inner->('foo');
#...
最重要的是,我认为两者都是等效的。
但是,第一个变体无法正常运行,因为Perl抱怨:
变量$ x在...
上不可用
...
中描述该行 $ x
在“本地子例程”中引用的线路。
谁能解释这一点? Perl的本地子例程与Pascal的本地子例程根本不同吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
问题中的术语“ local subroutine ”似乎是指。这些是私人子例程,仅在定义之后定义的范围(块)内可见;就像私人变量一样。
或
state
定义(或预定的)但是它们是用
我的
> sub subname {...} 在另一个内部的内部没有使其“本地”(在任何版本的perl中),但是将其编译成与其他子例程一起编写的,并将其放置在他们的软件包的符号表(main ::
例如)。问题提到 cloture> cloture 在标题中,这里是评论
a perl中的关闭是程序中的结构,通常是标量变量,引用子,并在其(运行时)创建其范围中带有环境(变量)。另请参阅a perlfaq7条目。凌乱解释。例如:
匿名子“关闭”范围中定义的变量,从某种意义上说,当它的生成函数返回其引用并删除范围并远离这些变量,这些变量仍然存在,因为该引用的存在。
由于在运行时创建了匿名subs,因此每次调用其生成函数时,它都会重新制作词汇,因此Anon Sub也是如此,因此它始终可以访问当前值。
因此,返回的对Anon-Sub的引用使用词汇数据,否则这些数据将消失。一小部分魔术。†
回到“本地”潜艇的问题。如果我们想引入实际关闭问题,我们需要从
offer
subroutine返回代码参考,例如或根据主要问题,如 v5.18.0 v5.26.0 ,我们可以使用一个命名的词汇(真正嵌套了(真正嵌套) !)
在这两种情况下,子例程
我的$ f = ofter(...);
的代码参考从ofert
返回,该参考正确使用了本地词汇变量($ $ X
),其最新值。但是我们不能使用
外部
闭合的平原sub in在编译时进行是全局的,因此它使用
ofter 从
ofter
首次称为时,将其值烘烤。因此,
才是正确的/代码>不。例如,我可以很容易地找到这篇文章,然后参见条目
Inner
只有在exter
下次称为ofter
中的词汇环境时,才能正确†,在我看来,在某种程度上,一个贫穷的对象,因为它具有功能性和数据,在另一个时间在其他地方制作,并且可以与传递给它的数据一起使用(并且都可以更新)
The term "local subroutine" in the question seems to be referring to lexical subroutines. These are private subroutines visible only within the scope (block) where they are defined, after the definition; just like private variables.
But they are defined (or pre-declared) with
my
orstate
, asmy sub subname { ... }
Just writing a
sub subname { ... }
inside of another doesn't make it "local" (in any version of Perl), but it is compiled just as if it were written alongside that other subroutine and is placed in their package's symbol table (main::
for example).The question mentions closure in the title and here is a comment on that
A closure in Perl is a structure in a program, normally a scalar variable, with a reference to a sub and which carries environment (variables) from its scope at its (runtime) creation. See also a perlfaq7 entry on it. Messy to explain. For example:
The anonymous sub "closes over" the variables in scope where it's defined, in a sense that when its generating function returns its reference and goes out of scope those variables still live on, because of the existence of that reference.
Since anonymous subs are created at runtime, every time its generating function is called and lexicals in it remade so is the anon sub, so it always has access to current values.
Thus the returned reference to the anon-sub uses lexical data, which would otherwise be gone. A little piece of magic.†
Back to the question of "local" subs. If we want to introduce actual closures to the question, we'd need to return a code reference from the
outer
subroutine, likeOr, per the main question, as introduced in v5.18.0 and stable from v5.26.0, we can use a named lexical (truly nested!) subroutine
In both cases
my $f = outer(...);
has the code reference returned fromouter
which correctly uses the local lexical variables ($x
), with their most current values.But we cannot use a plain named sub inside
outer
for a closureThis
inner
is made at compile time and is global so any variables it uses fromouter
will have their values baked from whenouter
was called the first time. Soinner
will be correct only untilouter
is called the next time -- when the lexical environment inouter
gets remade butinner
doesn't. As an example I can readily find this post, and see the entry in perldiag (or adduse diagnostics;
to the program).† And in my view a poor-man's object in a way, as it has functionality and data, made elsewhere at another time and which can be used with data passed to it (and both can be updated)
如果您需要“本地”潜艇,则可以根据所需的向后兼容性级别使用以下内容:
5.26+:
5.18+:
“任何”版本:
但是,您不应该使用
sub Inner {...}
。相同
基本上与
您基本上
,即使在
外部之外也可以看到
内部
,因此它根本不是“本地”。如您所见,对
*内部
的分配是在编译时完成的,这引入了另一个主要问题。5.18确实引入了词汇(“本地”)子例程。
如果您需要支持旧版本的Perl,则可以使用以下内容:
If you want "local" subs, you can use one of the following based on the level of backward compatibility you want:
5.26+:
5.18+:
"Any" version:
However, you should not, use
sub inner { ... }
.is basically the same as
so
is basically
As you can see,
inner
is visible even outside ofouter
, so it's not "local" at all.And as you can see, the assignment to
*inner
is done at compile-time, which introduces another major problem.5.18 did introduce lexical ("local") subroutines.
If you need to support older versions of Perl, you can use the following:
我从
Man Perldiag
中找到了一个很好的解释:因此,这是一个可能的解决方法:
...虽然不会:
I found a rather good explanation from
man perldiag
:So this would be a possible fix:
...while this one won't: