What is a closure, "This is a notion out of the Lisp world that says if you define an anonymous function in a particular lexical context, it pretends to run in that context even when it's called outside of the context." [2]. In object-oriented languages, "A closure is a callable object that
retains information from the scope in which it was created. From this definition, you can see that an inner class is an object-oriented closure, because it doesn't just contain each piece of information from the outer-class object ("the scope in which it was
created "), but it automatically holds a reference back to the whole outer-class object, where it has permission to manipulate all the members, even private ones.” 【3】
First look at this example:
#! / usr / bin / perl -w
use strict;
{
my $ inc = 10;
sub incr {
print "$ inc \ n";
$ inc ++;
}
}
incr ();
incr ();
#prints:
# 10
# 11
This example shows that named functions are global by default, even if they are defined in a block. We cannot quote the variable $ inc, but we can call the function.
#! / usr / bin / perl -w
use strict;
sub make_incr {
my $ inc = shift;
return sub {print "$ inc \ n"; $ inc ++};
}
my $ c1 = make_incr (10);
my $ c2 = make_incr (20);
$ c1-> ();
$ c2-> ();
$ c1-> ();
$ c2-> ();
#prints:
# 10
# 20
# 11
#twenty one
In this example, we can see that Perl's function return is actually an anonymous function reference. This is how Perl implements closures.
#! / usr / bin / perl -w
use strict;
sub exclaim {
my $ prefix = shift;
return sub {print "$ prefix $ _ [0]! \ n"};
}
my $ batman = exclaim ('Indeed');
my $ robin = exclaim ('Holy');
$ robin-> ('Mackerel'); # prints: Holy Mackerel!
$ batman-> ('Robin'); # prints: Indeed Robin!
So what does closure do? The following excerpt from "Learning Perl Objects, References & Modules" Chapter 6 [1]:
Usage 1: Return the reference of the subroutine in the subroutine, usually as a callback function:
use File :: Find;
sub create_find_callbacks_that_sum_the_size {
my $ total_size = 0;
return (sub {$ total_size + = -s if -f}, sub {return $ total_size});
}
my ($ count_em, $ get_results) = create_find_callbacks_that_sum_the_size ();
find ($ count_em, "bin");
my $ total_size = & $ get_results ();
print "total size of bin is $ total_size \ n";
This code is used to calculate the sum of the size of all files contained in a directory.
Usage 2: Use closed-loop variables as input and function generators to generate different function pointers:
#! / usr / bin / perl -w
use strict;
sub print_bigger_than {
my $ minimum_size = shift;
return sub {print "$ File :: Find :: name / n" if -f and -s> = $ minimum_size};
}
my $ bigger_than_1024 = print_bigger_than (1024);
find ($ bigger_than_1024, "bin");
print_bigger_than is equivalent to a function generator here. Different input variables can generate different function pointers. Here, a callback function that can print out file names with a file size greater than 1024 bytes is generated.
Usage 3: Used as a static local variable, it provides the function of static local variable in C language:
BEGIN {
my $ countdown = 10;
sub count_down {$ countdown--}
sub count_remaining {$ countdown}
}
The keyword BEGIN is used here. The role of BEGIN is to stop the current compilation after Perl compiles this code, and then directly enter the run phase, execute the code inside the BEGIN block. Then return to the compilation state and continue to compile the remaining code . This ensures that no matter where the BEGIN block is located in the program, before calling count_down, $ countdown is guaranteed to be initialized to 10.
Finally, attach a pretty cool example, come in "Perl Best Practices":
# Generate a new sorting routine whose name is the string in $ sub_name
# and which sorts on keys extracted by the subroutine referred to by $ key_sub_ref
sub make_sorter {
my ($ sub_name, $ key_sub_ref) = @_;
# Create a new anonymous subroutine that implements the sort ...
my $ sort_sub_ref = sub {
# Sort using the Schwartzian transform ...
return map {$ _-> [0]} # 3. Return original value
sort {$ a-> [1] cmp $ b-> [1]} # 2. Compare keys
map {[$ _, $ key_sub_ref-> ()]} # 1. Extract key, cache with value
@_; # 0. Perform sort on full arg list
};
# Install the new anonymous sub into the caller's namespace
use Sub :: Installer;
caller-> install_sub ($ sub_name, $ sort_sub_ref);
return;
}
# and then ...
make_sorter (sort_sha => sub {sha512 ($ _)});
make_sorter (sort_ids => sub {/ ^ ID: (\ d +) /});
make_sorter (sort_len => sub {length});
# and later ...
@names_shortest_first = sort_len (@names);
@names_digested_first = sort_sha (@names);
@names_identity_first = sort_ids (@names);
reference:
http://blog.csdn.net/mac_philips/article/details/6058946
http://unlser1.unl.csi.cuny.edu/faqs/perl-faq/Q3.14.html
Think in Java, 4th
http://www.itworld.com/nl/perl/08302001/
http://docstore.mik.ua/orelly/perl/advprog/ch04_03.htm