子例程与匿名子例程的上下文中的共享变量

时间:2013-05-07 17:32:56

标签: perl

我在另一篇文章的回答中看到了这段代码:Why would I use Perl anonymous subroutines instead of a named one?,但无法确切知道发生了什么,所以我想自己运行它。

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!

在上面的例子中,我收到一条警告:“变量$ 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

同样,我也不明白这个例子中发生了什么。有人可以解释一下吗?

提前致谢。

2 个答案:

答案 0 :(得分: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();

典型输出:

inner1: 123     SCALAR(0x80071f50)
inner2: 123     SCALAR(0x80071f50)
inner1: 456     SCALAR(0x80071f50)
inner2: 123     SCALAR(0x8002bcc8)

答案 1 :(得分:1)

你可以打印\& inner;在第一个例子中(定义后),并打印$ inner;在第二。

  

您看到的是十六进制代码引用,在第一个示例中相等,在第二个示例中有所不同。   所以,在第一个例子中,内部只创建了一次,并且它总是从外部()的第一次调用中封闭到$一个词法变量。