什么是闭包,“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】。在面向对象的语言里面,“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】
先看这个例子:
#!/usr/bin/perl -w use strict; { my $inc = 10; sub incr { print "$inc\n"; $inc++; } } incr(); incr(); #prints: #10 #11
这个例子说明命名函数默认是全局的,即使是定义在一个block里面。我们不能引用变量$inc,但是却可以调用函数。
#!/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 #21这个例子我们看到了,Perl的函数返回其实是一个匿名函数引用,这个就是magic所在了。这个也是Perl如何实现闭包的。
#!/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!
那么闭包有什么作用呢?以下摘自“Learning Perl Objects,References & Modules”的第6章【1】:
用法一 在subroutine中返回subroutine的引用,通常作为回调函数:
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";这段代码用于计算某个目录下所包含的所有文件的大小之和.
用法二 使用闭环变量作为输入,用作函数生成器,来生成不同的函数指针:
#!/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在这里相当于一个函数生成器,不同的输入变量可以生成不同的函数指针.这里生成了一个可以打印出文件大小大于1024字节文件名的回调函数.
用法三 作为静态局部变量使用,提供了c语言静态局部变量的功能:
BEGIN { my $countdown = 10; sub count_down { $countdown-- } sub count_remaining { $countdown } }这里用到了关键字BEGIN. BEGIN的作用就是,当perl编译完这段代码之后,停止当前编译,然后直接进入运行阶段,执行BEGIN块内部的代码.然后再回到编译状态, 继续编译剩余的代码. 这就保证了无论BEGIN块位于程序中的哪个位置,在调用count_down之前,$countdown被确保初始化为10.
最后附上一个相当cool的例子,来在“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);
参考:
- 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
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。