Perl callback functions and closures

Source: Internet
Author: User
Tags define function



In Perl, references to subroutines are often used to make callback functions (callback), closures (closure), especially anonymous subroutines.


callback function (callback)


For a callback function, see the article Understand: lexical scope, dynamic scope, callback function, closure



As an example of aFile::Findmodule's find function, it is used to search for a file under a given directory and then perform some operations on each of the searched files (by defining subroutines), which function to pass to the Find function, which is the callback function. Just like the Find command under UNIX, the files are found, and then the print, LS, exec cmd operations, which are the callback functions of the Find command.



use File::Find;

sub cmd {
    print "$File::Find::name\n";
};

find(\&cmd,qw(/perlapp /tmp/pyapp));


It$File::Find::namerepresents the full pathname of find found starting from the start path () and,/perlapp /tmp/pyappin addition, the default variable is assigned to find every file that is searched$_. It represents the basename of the file, not the same as the$File::Find::namefull path. For example:



Start path $File::Find::name $_
-------------------------------------------
   /perlapp /perlapp/1.pl 1.pl
   . ./a.log a.log
   Perlapp perlapp/2.pl 2.pl


Back to the question of the callback function. In the above example, a subroutine named CMD is defined, but it is not actively executing the subroutine, but instead it is put into the Find function, which is called by the Find function every time. This is like the "-print" option for Unix's Find command, where the function corresponding to the "-print" option is a callback function.



The above subroutine is only called once, no need to spend the brain cells to design its name, it can be designed as an anonymous subroutine, put into the find function.



use File::Find;

find(
    sub {
        print "$File::Find::name\n";
    },
    qw(/perlapp /tmp/pyapp)
);
Perl closures (closure) Brief introduction


For more information about closures, see the article Understanding: lexical scope, dynamic scope, callback function, closure



From the perspective of the Perl language to briefly describe the closure: subroutine 1 returns another subroutine 2, the subroutine 2 accesses the variable x in subroutine 1, when the subroutine 1 execution ends, the outside world can no longer access X, but the subroutine 2 because also refers to the variable x point to the data object, So that subroutine 2 can continue to access this data object after the end of subroutine 1.



Therefore, the variable x in subroutine 1 must be a lexical variable , otherwise, after the execution of subroutine 1, the variable x may still be accessed by the outside world, modify, if so, the closure and the normal function is meaningless.



A simple closure structure:


Sub sub1 {
     My $var1=N;
     $sub2 =sub {
         Do something about $var1
     }
     Return $sub2 # return a closure
}

$my_closure = sub1(); # Store the closure function to the subroutine reference variable


The main purpose is to let the subroutine sub1 internal nested sub-program$sub2can access the sub-program Sub1 but not sub$sub2-program variables, so that, as long as the sub1 return of the closure assignment to give$my_closure, you can let the closure function has been reference$var1Variable corresponding to the numeric object, but after the execution of the sub1, the outside world can no longer$var1access the data object (because it is a lexical variable). That is, when Sub1 executes,$var1the data object pointed to is accessible only by the closure$my_closure.



A typical Perl closure:



Sub how_many { # define function
     My $count=2; # lexical variable $count
     Return sub {print ++$count,"\n"}; # Returns an anonymous function, which is an anonymous closure
}

$ref=how_many(); # Assign the closure to the variable $ref

How_many()->(); # (1) Call anonymous closure: output 3
How_many()->(); # (2) Call anonymous closure: output 3
$ref->(); # (3) Call named closure: output 3
$ref->(); # (4) Call the named closure again: output 4


The closure is assigned to the above,$refby$refcalling this closure, even if the how_many in$counthow_many () will disappear (because it is a lexical variable, the outside world can not access), but the$refpoint of the closure function is still referencing the variable, So multiple calls$refwill change$countthe value, so the above (3) and (4) First output 3, and then output the changed 4. The outputs of the above (1) and (2) are 3, because two how_many () functions return a separate anonymous closure, and the data object 3 disappears after the statement executes.



The Perl language has its own peculiarities, especially when it supports only the execution of a block of statements (that is, surrounded by curly braces{}), which makes it necessary for Perl to create a closure that does not necessarily require a function nesting, but simply puts a function into a statement block:



My $closure;
{
     My $count=1; # lexical variable that disappears with the statement block
     $closure = sub {print ++$count,"\n"}; # Closure function
}

$closure->(); # Call a closure function, output 2
$closure->(); # Call the closure function again, output 3


In the above code, the$countreference number at the time of assignment is 1, used in sub and assigned to the$closurereference number 2, when exiting the code block, thecountreference number is reduced to 1, because this is a lexical variable, after the exit code block can not be accessed by the outside$count, but the closure$closurehave been able to continue to visit.



Closures are actually a variety of forms. In layman's terms, as long as a subroutine 1 can access another subroutine 2 in the variable, and the subroutine 1 will not be executed with the subroutine 2 to complete the loss of variables, it belongs to the closure. Of course, for Perl, sub-Program 2 may not be necessary, as in the example above.



For example, the following code snippet does not belong to a closure:



$y=3;
sub mysub1 {
    $x=shift;
    $x+$y;
}

$nested_ref=\&mysub1;

sub mysub2 {
    $x=1;
    $z=shift;
    return $nested_ref->($z);
}

print mysub2(2);


$nested_refone instance of subroutine Mysub1 is returned for MYSUB2, but Mysub1 is used in a$yglobal variable instead of a mysub2, and MYSUB2 does not disappear after execution, and$yit seems unnecessary for the closure package.


Perl Closure Applications


For example, theFile::Findmodule's Find function calculates the number of files in a given directory:



Use File::Find;
My $callback;
{
My $count = 0;
$callback = sub { print ++$count, ": $File::Find::name\n" };
}
Find($callback, '.'); # return quantity and file name
Find($callback, '.'); # Execute again, the number will be incremented based on the previous find


Perl has a strong syntax and can return multiple closures at once:



use File::Find;
sub sub1 {
    my $total_size = 0;
    return(sub { $total_size += ?s if ?f }, sub { return $total_size });
}
my ($count_em, $get_results) = sub1( );
find($count_em, '/bin');
find($count_em, '/boot');
my $total_size = &$get_results( );
print "total size of /bin and /boot: $total_size\n";


The above two closures, because the same object is referenced at the same time, so$count_emthe lexical variables of the closure modification$get_resultscan also be accessed.



Or:



{
    my $count=10;
    sub one_count{ ++$count; }
    sub get_count{ $count; }
}

one_count();
one_count();
print get_count();


Because the subroutine in the code block has a name, the two subroutines are still valid after the block ends (after the block ends, the variable is invalid because the My modifier is added).



But what if you put the call statement in front of the code block?



One_count(); # 1
One_count(); # 2
Print get_count(); # output: 2

{
     My $count=10;
     Sub one_count{ ++$count; }
     Sub get_count{ $count; }
}


The above output 2, that$count=10is, the assignment 10 behavior is invalid. This is because the declaration and initialization of a lexical variable (initialized to undef) is done during compilation, and the assignment operation is performed at the time it is executed. Therefore, when the compilation is completedone_count()and executed to this statement, the compiled subroutine One_count is called, but it has not been executed to the statement block, so$countthe assignment has not been executed.



You can add the above statement block to the BEGIN block:



one_count();  # 11
one_count();  # 12
print get_count();  # 输出:12

BEGIN{
    my $count=10;
    sub one_count{ ++$count; }
    sub get_count{ $count; }
}
State modifier instead of simple closure


The function of the front closure is already very obvious, that is, in order to let the lexical variable cannot be accessed externally, but let the subroutine continue to access it.



Perl provides a state modifier, which is exactly the same as my lexical variable, except that the state modifier makes the variable persistent, but is inaccessible to the outside world (because it is a lexical variable), and the state-modified variable initializes the assignment once.



Attention:


    • The state modifier is not only used in subroutines, but can be used in any block of statements, such as the block of statements in Find, grep, and map.
    • As long as nothing is referencing the state variable, it will be recycled.
    • At present state can only modify scalar, modified array, hash will be error. But you can modify the reference variable of the array, hash, because the reference is a scalar


For example, move a state-modified variable from an outer subroutine to an inner-layer self-order. The following two sub-programs are equivalent:



Sub how_many1 {
     My $count=2;
     Return sub {print ++$count,"\n"};
}

Sub how_many2 {
     Return sub {state $count=2;print ++$count,"\n"};
}

$ref=how_many2(); # Assign the closure to the variable $ref
$ref->(); # (1) Call named closure: output 3
$ref->(); # (2) Call the named closure again: output 4


It is important to note that although thestate $count=2same closure is executed multiple times, it is not re-assigned to 2, but is assigned at the time of initialization.



Also, placing the subroutine call statement in front of the subroutine definition statement can be run as expected (the previously parsed closure will not run as expected):



$ref=how_many2(); # Assign the closure to the variable $ref
$ref->(); # (1) Call named closure: output 3
$ref->(); # (2) Call the named closure again: output 4 


This is because itstate $count=2is part of the subroutine and executes the sentence assignment statement wherever it is called.



Perl callback functions and closures


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.