子例程引用与闭包:

来源:互联网 发布:数据统计分析基础 编辑:程序博客网 时间:2024/06/05 16:18
和普通变量一样,子例程(subroutine)可以是有名的也可以是匿名的,而且Perl语法上支持对任何一种类型的引用。1. 调度表(dispatch table),它是一种将事件映射到子例程引用的数据结构。每当事件发生时,就会通过一张调度表来查找与之相关的子例程。2.闭包(Closure),闭包是这样一种子例程,创建时,它将包含其子例程的环境打包(包括所有它需要的和不局部与其本身的变量)。子例程引用:对有名子例程的引用:我们前面就已经讲过,要创建对现存变量的引用,只需给它加上反斜杠前缀。对于子例程也大致如下,如\&mysub就是对&mysub的引用[oracle@oadb 4]$ cat a1.pl sub greet {   print "hello\n";};$rs=\&greet; ##创建对子例程greet的引用&$rs;[oracle@oadb 4]$ perl a1.pl hello[oracle@oadb 4]$ cat a2.pl sub greet {   print "hello\n";};$rs=\&greet(); ##创建对子例程greet的引用&$rs;[oracle@oadb 4]$ perl a2.pl helloNot a CODE reference at a2.pl line 7.[oracle@oadb 4]$ 对匿名子例程的引用:你只需省略子例程声明中的过程名即可创建匿名子例程,除了这一点外,其声明同有名字例程完全一样:[oracle@oadb 4]$ cat a3.pl $rs=sub{   print "hello \n";};print &$rs;[oracle@oadb 4]$ perl a3.pl hello 1[oracle@oadb 4]$ 对子例程引用的间接访问:对子例程引用的间接访问(dereference)将会间接的调用该子例程。和数据引用一样,Perl并不关心$rs指向的有名还是无名的子例程。[oracle@oadb 4]$ cat a4.pl sub greet {   my $a=shift;   my $b=shift;   return $a+$b;};my $rs=\&greet;print &$rs(10,20);[oracle@oadb 4]$ perl a4.pl 30[oracle@oadb 4]$ [oracle@oadb 4]$ cat a4.pl sub greet {   my $a=shift;   my $b=shift;   return $a+$b;};my $rs=\&greet;print $rs->(10,20);[oracle@oadb 4]$ perl a4.pl 30[oracle@oadb 4]$ 使用子例程引用:让我们来看一些子例程引用的常见例子:回调函数与高等级子例程:回调函数就是通过引用来使用的普通子例程。调度表 典型的调度表就是一个包含子例程引用的数组[oracle@oadb 4]$ cat a5.pl  %options = (   #针对每个选项调用相应的子例程     "-h" =>\&help,     "-f" =>sub{$a='abcdef'},     "-r" =>sub {$b=1});sub ProcessArgs {  ##注意记号的意义,r1表示指向数组的引用,rh表示指向散列表的引用  my $rlArgs=shift;  my $rhOptions=shift;  foreach $arg (@$rlArgs){    if (exists $rhOptions->{$arg}){         #其值一定是指向子例程的引用         $rsub = $rhOptions->{$arg};         print &$rsub;         print "\n";}}};my @arr=("-h","-f");sub help{   return 78 + 21;};&ProcessArgs(\@arr,\%options);    [oracle@oadb 4]$ perl a5.pl 99abcdef闭包:不仅可以返回数据,Perl的子例程还可以返回一个指向子例程的引用。[oracle@oadb 4]$ cat a6.pl use Data::Dumper;$greeting ="hello world";$rs=sub {   print $greeting;};print $rs;print "\n";print Dumper($rs);print "\n";print &$rs;[oracle@oadb 4]$ perl a6.pl CODE(0x1b0a660)$VAR1 = sub { "DUMMY" };hello world1[oracle@oadb 4]$ 在这个例子中,匿名子例程利用了全局变量$greeting[oracle@oadb 4]$ cat a7.pl sub generate_greeting {   my $greeting="hello world";   return sub{print $greeting};};$rs=generate_greeting();&$rs();[oracle@oadb 4]$ perl a7.pl hello world[oracle@oadb 4]$ [oracle@oadb 4]$ 让我们再来改动一下这段代码,以更好地理解闭包这个专业用语究竟能做什么:[oracle@oadb 4]$ cat a8.pl sub generate_greeting {    my $greeting = shift;    return sub {      my $subject=shift;      print "$greeting $subject abcdefg\n";   }};$rs1=generate_greeting("hello");print &$rs1;print "\n";print &$rs1("world");  [oracle@oadb 4]$ perl a8.pl hello  abcdefg1hello world abcdefg1[oracle@oadb 4]$ 闭包的内幕:闭包的应用:智能回调当用户按下按钮时,回调过程将被调用,并使用它所保存的$title的值。    use Tk;  ##创建顶层窗口  my $mw = MainWindow->new(-title => "Mem monitor");  ##创建两个按钮,这些按钮将在被按下打印自己的名字  CreateButton($mw,"hello");    CreateButton($mw,"world");    sub CreateButton {     my ($parent,$title)=@_;     my $b;     $callback_proc=sub {             print "Button $title pressed\n";             };             $frm_name1 = $mw->Frame()->pack(-side=>"top",-fill => 'x');      $b=$frm_name1->Button (           '-text'=>"title",           '-fg'=>'red',           '-command'=>$callback_proc  );      $b->pack();  };  MainLoop;                 C:\Users\TLCB\Desktop\perl>perl testtk.pl  Button hello pressed  Button hello pressed  Button hello pressed  Button world pressed  Button world pressed  Button world pressed  Button world pressed  Button world pressed  Button world pressed    


                                             
0 0
原创粉丝点击