11.4. Taking References to FunctionsProblemYou need to manipulate a subroutine by reference. This might happen if you need to create a signal handler, a Tk callback, or a hash of function pointers. SolutionTo get a code reference: $cref = \&func; $cref = sub { ... }; To call a code reference: @returned = $cref->(@arguments); @returned = &$cref(@arguments); Discussion
If the name of a function is
Perl 5.004 introduced the postfix arrow notation for dereferencing a code reference. Prior to that, to call a subroutine by reference, you had to say $funcname = "thefunc"; &$funcname();
that's not a very good solution for several reasons. First, it uses symbolic references, not real (hard) references, so it is forbidden under the Second, it doesn't include package information, so if executed in a different package, it would try to call the wrong function. Finally, in the odd case that the function were redefined at some point, the symbolic reference would get whatever the current definition for the function was, whereas the hard reference would retain its old definition. Instead of placing the name of the function in the variable, use the backslash operator to create a reference to the function. This is the normal way to store a function in a variable or pass it to another function. You can mix and match references to named functions with references to unnamed ones: my %commands = ( "happy" => \&joy, "sad" => \&sullen, "done" => sub { die "See ya!" }, "mad" => \&angry, ); print "How are you? "; chomp($string = <STDIN>); if ($commands{$string}) { $commands{$string}->(); } else { print "No such command: $string\n"; }
If you create an anonymous function that refers to a lexical ( sub counter_maker { my $start = 0; return sub { # this is a closure return $start++; # lexical from enclosing scope }; } $counter = counter_maker(); for ($i = 0; $i < 5; $i ++) { print &$counter, "\n"; }
Even though $counter1 = counter_maker(); $counter2 = counter_maker(); for ($i = 0; $i < 5; $i ++) { print &$counter1, "\n"; } print &$counter1, " ", &$counter2, "\n"; Closures are often used in callback routines. In graphical and other event-based programming, you associate code with a keypress, mouse click, window expose event, etc. The code will be called much later, probably from an entirely different scope. Variables mentioned in the closure must be available when it's finally called. To work properly, such variables must be lexicals, not globals.
Another use for closures is function generators, that is, functions that create and return brand new functions. sub timestamp { my $start_time = time(); return sub { return time() - $start_time }; } $early = timestamp(); sleep 20; $later = timestamp(); sleep 10; printf "It's been %d seconds since early.\n", $early->(); printf "It's been %d seconds since later.\n", $later->();
Each call to See AlsoThe section on "Closures" in Chapter 4 of Programming Perl and the discussion on closures in perlref (1); Recipe 10.11 ; Recipe 11.4 |
|