第<4>章 子例程引用与闭包

来源:互联网 发布:始作俑者 其无后乎孟子 编辑:程序博客网 时间:2024/05/16 13:58
和普通变量一样,子例程(subroutine) 可以是有名的也可以是匿名的,而且Perl 语法上支持对任何一种类型的引用。对有名子例程的引用:我们前面已经讲过,要创建对现存变量的引用,只需给它加上反斜杠前缀。对子例程也大致如此,如\&mysub 就是对&mysub的引用,又比如:zjzc01:/root/hei# cat a24.pl sub greet {  print "hello \n";};$rs = \&greet;  #创建对子例程greet的引用&$rs;zjzc01:/root/hei# perl a24.pl hello zjzc01:/root/hei# cat a24.pl sub greet {  print "hello \n";};$rs = \&greet;&$rs;$var=&$rs;print $var;print "\n";zjzc01:/root/hei# perl a24.pl hello hello 1该表达式的结果可能不是你所希望的,它调用greet,然后创建了一个对其返回值的引用也就是子例程中最后一个表达式的值是引用。由于print 最后执行并返回1或0(表明是否成功打印了后面的值),因此该表达式的结果就是一个对值为1或者0的标量变量的引用对匿名子例程的引用:你只需要省略掉子例程声明中的过程名即可创建匿名子例程。除了这一点外,其声明同有名字例程完全一样:zjzc01:/root/hei# cat a25.pl $rs = sub{print "hello\n";};$var= &$rs;print "111111111\n";print $var;print "\n";zjzc01:/root/hei# perl a25.pl hello1111111111zjzc01:/root/hei# cat a25.pl print sub{print "hello\n";};print "\n";print &{sub{print "hello\n";}};print "\n";zjzc01:/root/hei# perl a25.pl CODE(0x244a2f0)hello1 $client->on_receive_msg = sub{        my $msg = shift ;zjzc01:/root/hei# cat a25.pl $var= sub{print "hello\n";};print $var;print "\n";print &$var;print "\n";$x=&$var; print "\$x is $x\n";zjzc01:/root/hei# perl a25.pl CODE(0xa38320)hello1hello$x is 1对子例程引用的间接访问:对子例程引用的间接访问(dereference) 将会间接的调用该子例程。和数据引用一样,Perl并不关心$rs指向的有名还是无名的子例程,间接访问操作对两种情况都适合;使用子例程引用:让我们来看一些子例程引用的常见例子:回调函数与高级子例程my (@frames,@button);        my %sub_of = (    "日志查询" => \&push_button2 ,        "温金短信查询" => \&push_button3 ,        "中均短信查询" => \&push_button4 ,                "机器信息查询" => \&push_button5,        "IP信息查询" => \&push_button6,        "设备信息维护" => \&push_button7,        "test" => sub{ print "program 6" },        7 => sub{ print "program 7" }, ##函数引用        8 => sub{ print "program 8" },        9 => sub{ print "program 9" },);~                                                                                                                回调函数就是通过引用来使用的普通子例程,调用者(那些引用使用者)                                                                               调度表:典型的调度表就是一个包含子例程引用的数组,下面的例子中,%options 就是一个将命令行选项映射到不同字例程的调度表:%options = (  ##针对每个选项调用相应的子例程"-h"   =>\&help;"-f"   =>sub{$askNoQuestions=1},"-r"   =>sub{$recursive=1},"_default_" => \&default.);闭包:不仅可以返回数据,Perl的子例程还可以返回一个指向子例程的引用。这同其他别的传递子例程引用的方法没有什么不同,但是有一点是个例外,这是一种涉及匿名子例程和词法变量(my) 的隐含特性。考虑下面的例子:zjzc01:/root/hei# cat a26.pl $greeting = "hello world";$rs = sub{ print $greeting;};&$rs();print "\n";print "1111111111\n";$var=$rs;print $var;print "\n";print &$var;print "\n";zjzc01:/root/hei# perl a26.pl hello world1111111111CODE(0x718368)hello world1----------------------------------zjzc01:/root/hei# cat a26.pl $greeting = "hello world";$rs = sub{ return $greeting;};&$rs();print "\n";print "1111111111\n";$var=$rs;print $var;print "\n";print &$var;print "\n";zjzc01:/root/hei# perl a26.pl 1111111111CODE(0x1795368)hello world         zjzc01:/root/hei# cat a27.pl sub generate_greeting{  my ($greeting) = "hello world";  return sub{print $greeting}; ##返回引用};$rs=&generate_greeting;print $rs;print "\n";print &$rs;print "\n";zjzc01:/root/hei# perl a27.pl CODE(0xeded48)hello world1闭包的应用:闭包以两种似乎毫无相关的方式来应用。最常见的方式就是用"智能调用"回调子例程由于闭包是一些包含少量私有数据的子例程引用,因此它们可以方便的应用在图形用户界面的回调过程中:闭包与对象的对比:对象通俗的定义是一组数据与函数的集合,数据提供对象函数操作的环境。比如,$buttion->setForeground("yellow")中, setForeground 函数会自动知道你指的是哪个按钮从某种意义上说,闭包也提供了同样的机制---它也是一种子例程与只对子例程可见的私有数据的结合。

0 0
原创粉丝点击