zoukankan      html  css  js  c++  java
  • 第章 子例程引用与闭包

    和普通变量一样,子例程(subroutine) 可以是有名的也可以是匿名的,而且Perl 语法上支持对任何一种类型的引用。
    
    
    对有名子例程的引用:
    
    我们前面已经讲过,要创建对现存变量的引用,只需给它加上反斜杠前缀。对子例程也大致如此,
    
    如&mysub 就是对&mysub的引用,又比如:
    
    zjzc01:/root/hei# cat a24.pl 
    sub greet {
      print "hello 
    ";
    };
    
    $rs = &greet;  #创建对子例程greet的引用
    &$rs;
    zjzc01:/root/hei# perl a24.pl 
    hello 
    
    
    zjzc01:/root/hei# cat a24.pl 
    sub greet {
      print "hello 
    ";
    };
    
    $rs = &greet;
    &$rs;
    $var=&$rs;
    print $var;
    print "
    ";
    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
    ";};
    
    $var= &$rs;
    print "111111111
    ";
    print $var;
    print "
    ";
    
    zjzc01:/root/hei# perl a25.pl 
    hello
    111111111
    1
    
    zjzc01:/root/hei# cat a25.pl 
    print sub{print "hello
    ";};
    print "
    ";
    print &{sub{print "hello
    ";}};
    print "
    ";
    
    
    zjzc01:/root/hei# perl a25.pl 
    CODE(0x244a2f0)
    hello
    1
    
    
    
    
     $client->on_receive_msg = sub{
            my $msg = shift ;
    
    
    
    zjzc01:/root/hei# cat a25.pl 
    $var= sub{print "hello
    ";};
    print $var;
    print "
    ";
    print &$var;
    print "
    ";
    $x=&$var; print "$x is $x
    ";
    
    
    
    zjzc01:/root/hei# perl a25.pl 
    CODE(0xa38320)
    hello
    1
    hello
    $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 "
    ";
    print "1111111111
    ";
    $var=$rs;
    print $var;
    print "
    ";
    print &$var;
    print "
    ";
    zjzc01:/root/hei# perl a26.pl 
    hello world
    1111111111
    CODE(0x718368)
    hello world1
    
    ----------------------------------
    zjzc01:/root/hei# cat a26.pl 
    $greeting = "hello world";
    
    $rs = sub{ return $greeting;};
    
    &$rs();
    print "
    ";
    print "1111111111
    ";
    $var=$rs;
    print $var;
    print "
    ";
    print &$var;
    print "
    ";
    zjzc01:/root/hei# perl a26.pl 
    
    1111111111
    CODE(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 "
    ";
    print &$rs;
    print "
    ";
    zjzc01:/root/hei# perl a27.pl 
    CODE(0xeded48)
    hello world1
    
    
    闭包的应用:
    
    闭包以两种似乎毫无相关的方式来应用。最常见的方式就是用"智能调用"回调子例程
    
    
    由于闭包是一些包含少量私有数据的子例程引用,因此它们可以方便的应用在图形用户界面的回调过程中:
    
    
    
    闭包与对象的对比:
    
    
    对象通俗的定义是一组数据与函数的集合,数据提供对象函数操作的环境。
    
    比如,$buttion->setForeground("yellow")中, setForeground 函数会自动知道你指的是哪个按钮
    
    
    从某种意义上说,闭包也提供了同样的机制---它也是一种子例程与只对子例程可见的私有数据的结合。
    
    
    
    
    
    
    
    
    
    

  • 相关阅读:
    k8s的基本概念与基本功能
    STM32F030看门狗
    STM32F030低功耗
    STM32开发脱坑记
    ubuntu下安装wine并运行source insight
    Linux下使用Eclipse搭建ARM开发环境
    linux下的find文件查找命令与grep文件内容查找命令(转)
    STM32F030 BootLoader与应用程序的跳转设置
    MCU开发之MDK-ARM总结
    IIC协议总结
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13351107.html
Copyright © 2011-2022 走看看