Perl callback functions and closures

Source: Internet
Author: User

Tags: meaning count () amp returns persistent one ash default cmd

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 a File::Find module'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::name represents the full pathname of find found starting from the start path () and, /perlapp /tmp/pyapp in 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::name full path. For example:

  起始路径     $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   # 返回一个闭包}$my_closure = sub1();    # 将闭包函数存储到子程序引用变量

The main purpose is to let the subroutine sub1 internal nested sub-program $sub2 can 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 $var1 Variable corresponding to the numeric object, but after the execution of the sub1, the outside world can no longer $var1 access the data object (because it is a lexical variable). That is, when Sub1 executes, $var1 the data object pointed to is accessible only by the closure $my_closure .

A typical Perl closure:

sub how_many {       # 定义函数    my $count=2;     # 词法变量$count    return sub {print ++$count,"\n"};  # 返回一个匿名函数,这是一个匿名闭包}$ref=how_many();    # 将闭包赋值给变量$refhow_many()->();     # (1)调用匿名闭包:输出3how_many()->();     # (2)调用匿名闭包:输出3$ref->();           # (3)调用命名闭包:输出3$ref->();           # (4)再次调用命名闭包:输出4

The closure is assigned to the above, $ref by $ref calling this closure, even if the how_many in $count how_many () will disappear (because it is a lexical variable, the outside world can not access), but the $ref point of the closure function is still referencing the variable, So multiple calls $ref will change $count the 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;   # 随语句块消失的词法变量    $closure = sub {print ++$count,"\n"};  # 闭包函数}$closure->();  # 调用一次闭包函数,输出2$closure->();  # 再调用一次闭包函数,输出3

In the above code, the $count reference number at the time of assignment is 1, used in sub and assigned to the $closure reference number 2, when exiting the code block, the count reference 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 $y global variable instead of a mysub2, and MYSUB2 does not disappear after execution, and $y it seems unnecessary for the closure package.

Perl Closure Applications

For example, the File::Find module'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, '.');    # 返回数量和文件名find($callback, '.');    # 再次执行,数量将在上一个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_em the lexical variables of the closure modification $get_results can 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();  # 1one_count();  # 2print get_count();  # 输出:2{    my $count=10;    sub one_count{ ++$count; }    sub get_count{ $count; }}

The above output 2, that $count=10 is, 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 completed one_count() and executed to this statement, the compiled subroutine One_count is called, but it has not been executed to the statement block, so $count the assignment has not been executed.

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

one_count();  # 11one_count();  # 12print get_count();  # 输出:12BEGIN{    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();   # 将闭包赋值给变量$ref$ref->();           # (1)调用命名闭包:输出3$ref->();           # (2)再次调用命名闭包:输出4

It is important to note that although the state $count=2 same 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();   # 将闭包赋值给变量$ref$ref->();           # (1)调用命名闭包:输出3$ref->();           # (2)再次调用命名闭包:输出4sub how_many2 {    return sub {state $count=2;print ++$count,"\n"};}

This is because it state $count=2 is 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.

Tags Index: