我在另一篇文章的答案中看到了这段代码:为什么我会使用Perl匿名子程序而不是命名的子程序?,但无法确切地知道发生了什么,所以我想自己运行它.
sub outer
{
my $a = 123;
sub inner
{
print $a, "\n"; #line 15 (for your reference, all other comments are the OP's)
}
# At this point, $a is 123, so this call should always print 123, right?
inner();
$a = 456;
}
outer(); # prints 123
outer(); # prints 456! Surprise!
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,我收到一个警告:"变量$ a不会在第15行保持共享.显然,这就是输出"意外"的原因,但我仍然不明白这里发生了什么.
sub outer2
{
my $a = 123;
my $inner = sub
{
print $a, "\n";
};
# 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
outer2(); # prints 123
outer2(); # prints 123
Run Code Online (Sandbox Code Playgroud)
同样,我也不明白这个例子中发生了什么.有人可以解释一下吗?
提前致谢.
mob*_*mob 13
它与子程序的编译时与运行时解析有关.正如diagnostics
消息所说,
当调用内部子程序时,它将看到外部子程序变量的值,就像它在第一次 调用外部子程序之前和期间一样; 在这种情况下,在第一次调用外部子程序完成后,内部子程序和外部子程序将不再共享该变量的公共值.换句话说,该变量将不再共享.
注释您的代码:
sub outer
{
# 'my' will reallocate memory for the scalar variable $a
# every time the 'outer' function is called. That is, the address of
# '$a' will be different in the second call to 'outer' than the first call.
my $a = 123;
# the construction 'sub NAME BLOCK' defines a subroutine once,
# at compile-time.
sub inner1
{
# since this subroutine is only getting compiled once, the '$a' below
# refers to the '$a' that is allocated the first time 'outer' is called
print "inner1: ",$a, "\t", \$a, "\n";
}
# the construction sub BLOCK defines an anonymous subroutine, at run time
# '$inner2' is redefined in every call to 'outer'
my $inner2 = sub {
# this '$a' now refers to '$a' from the current call to outer
print "inner2: ", $a, "\t", \$a, "\n";
};
# At this point, $a is 123, so this call should always print 123, right?
inner1();
$inner2->();
# if this is the first call to 'outer', the definition of 'inner1' still
# holds a reference to this instance of the variable '$a', and this
# variable's memory will not be freed when the subroutine ends.
$a = 456;
}
outer();
outer();
Run Code Online (Sandbox Code Playgroud)
典型输出:
inner1: 123 SCALAR(0x80071f50)
inner2: 123 SCALAR(0x80071f50)
inner1: 456 SCALAR(0x80071f50)
inner2: 123 SCALAR(0x8002bcc8)
Run Code Online (Sandbox Code Playgroud)