第四章 子例程引用与闭包

和普通变量一样,子例程(subroutine)可以是有名的也可以是匿名的,而且Perl 语法上支持对任何一种类型的引用。

这种引用很像C语言中指向函数的指针,它可以被用来创建如下复杂的结构:

闭包(Closure).闭包是这样一种字例程,创建时,它将包含其子例程的环境打包。

子例程引用:

子例程并没有什么特别或神奇的地方,在这一节我们要学习如何创建对有名的和匿名的子例程的引用

对有名子例程的引用:

我们前面就已经讲过,要创建对现存变量的引用,只需给它加上反斜杠前缀。对于子例程也大致如此,

如&mysub 就是对&mysub的引用。又比如:

[root@master perl]# cat m12.pl
sub greet {
print “hello ”;
}
rs=&greet;printrs,” ”;
rs=&greet();printrs,” ”;

[root@master perl]# perl m12.pl
CODE(0x25c0c48)
hello
SCALAR(0x25ac178)

有重要的一点需要说明,我们并没有在此调用子例程greet,这和创建对标量变量的引用时一样,也没有计算标量变量的值。

与下面带有圆括号的代码作一对比:

$rs=&greet();

对匿名子例程的引用:

你只需要省略掉子例程声明中的过程名即可创建匿名子例程。除了这一点外,其声明同有名子例程完全一样。

[root@master perl]# cat m12.pl
rs=sub{  
 print “hello  ”;  
};  
&
rs;
[root@master perl]# perl m12.pl
hello

对子例程引用的间接访问:

对于子例程引用的间接访问(dereference)将会间接的调用该子例程。

和数据引用一样,Perl并不关心$rs指向的有名还是无名的子例程:

my %sub_of = (
“日志查询” => &push_button2 ,
“VIEW MEMORY” => &push_button2 ,
“VIEW DISK” =>

&push_button3 ,
4 => sub{ print “program 4” },
5 => sub{ print “program 5” },
6 => sub{

print “program 6” },
7 => sub{ print “program 7” },
8 => sub{ print “program 8” },
9 =>

sub{ print “program 9” },
);

这里是子程序的引用:

闭包:

[root@master perl]# cat m13.pl
greeting=helloworld;rs = sub{
print greeting;  
};  
&
rs();
[root@master perl]# perl m13.pl
hello world[root@master perl]#

在这个例子中,匿名子例程利用了全局变量$greeting,没什么特别的。

[root@master perl]# cat m15.pl
sub generate_greeting{
return sub {print “xxxxxxx”};
}

rs=generate_greeting();  
&
rs();
[root@master perl]# perl m15.pl
xxxxxxx

闭包就是一些保留这在其创建时所在域中需要的变量。

Perl 创建的闭包恰好只针对(my)词法变量而不对全局或局部化(使用local)变量。

[root@master perl]# cat m16.pl
callbackproc=subprintxxxxxxxx ;;printcallback_proc,” ”;
print &$callback_proc;

[root@master perl]# perl m16.pl
CODE(0x7c9c60)

xxxxxxxx

[root@master perl]# cat m17.pl
sub gererate_greeting{
my (greeting) = “hello world”;  
  return sub{print
greeting};
}

rs=gererate_greeting();  
&
rs();

[root@master perl]# perl m17.pl
hello world[root@master perl]#

sub{print $greeting} 这里是引用

让我们再来改动一下这段代码,以更好地理解闭包这个专业用语究竟能做什么:

闭包的应用;

闭包以两种似乎毫不相关的方式来应用,最常见的用法是用”智能” 回调子例程。

将闭包用作”智能”回调

由于闭包是一些包含少量私有数据的子例程引用,因为它们可以方便的应用在图形用户界面的回调过程中。

举例来说,你使用Tk工具包创建了一个按钮,并赋予它一个指向子例程的引用。当按钮被按下时将回调该子例程。

CreateButton 创建了一个GUI的按钮,并提供给它一个指向匿名子例程的引用($callback_proc),

它将依附于其环境中的my变量title.,,使title的值。

闭包和对象的对比:

对象通俗的定义就是一组数据与函数的集合,数据提供对象函数操作的环境。比如,

$button->setForground(“yellow”)中,>setForground函数会自动知道你指的是哪个按钮。

原文地址:https://www.cnblogs.com/hzcya1995/p/13351343.html