Документация
HTML CSS PHP PERL другое

Section 7.7.  Closure Variables as Static Local Variables

 
Previous
Table of Contents
Next

7.7. Closure Variables as Static Local Variables

A subroutine doesn't have to be an anonymous subroutine to be a closure. If a named subroutine accesses lexical variables, and those variables go out of scope, the named subroutine retains a reference to the lexicals, just as you saw with anonymous subroutines. For example, consider two routines that count coconuts for Gilligan:

{
  my $count;
  sub count_one { ++$count }
  sub count_so_far { return $count }
}

If we place this code at the beginning of the program, we declare the variable $count inside the naked block scope, and the two subroutines that reference the variable become closures. However, because they have a name, they will persist beyond the end of the scope (as do all named subroutines). Since the subroutines persist beyond the scope and access variables declared within that scope, they become closures and thus can continue to access $count throughout the lifetime of the program.

So, with a few calls, we can see an incremented count:

count_one(  );
count_one(  );
count_one(  );
print 'we have seen ', count_so_far(  ), " coconuts!\n";

$count retains its value between calls to count_one( ) or count_so_far( ), but no other section of code can access this $count at all.

In C, this is known as a static local variable: a variable that is visible to only a subset of the program's subroutines but persists throughout the life of the program, even between calls to those subroutines.

What if we wanted to count down? Something like this will do:

{
  my $countdown = 10;
  sub count_down { $countdown-- }
  sub count_remaining { $countdown }
}

count_down(  );
count_down(  );
count_down(  );
print 'we're down to ', count_remaining(  ), " coconuts!\n";

That is, it'll do as long as we put it near the beginning of the program, before any invocations of count_down( ) or count_remaining( ). Why?

This block doesn't work when you put it after those invocations because there are two functional parts to the first line:

my $countdown = 10;

One part is the declaration of $countdown as a lexical variable. That part is noticed and processed as the program is parsed during the compile phase. The second part is the assignment of 10 to the allocated storage. This is handled as Perl executes the code during the run phase. Unless Perl executes the run phase for this code, the variable has its initial undef value.

One practical solution to this problem is to change the block in which the static local appears into a BEGIN block:

BEGIN {
  my $countdown = 10;
  sub count_down { $countdown-- }
  sub count_remaining { $countdown }
}

The BEGIN keyword tells the Perl compiler that as soon as this block has been parsed successfully (during the compile phase), jump for a moment to run phase and run the block as well. Presuming the block doesn't cause a fatal error, compilation then continues with the text following the block. The block itself is also discarded, ensuring that the code within is executed precisely once in a program, even if it had appeared syntactically within a loop or subroutine.


Previous
Table of Contents
Next
© 2000- NIV