和普通变量一样,子例程(subroutine)可以是有名的也可以是匿名的,而且Perl 语法上支持对任何一种类型的引用。
这种引用很像C语言中指向函数的指针,它可以被用来创建如下复杂的结构:
闭包(Closure).闭包是这样一种字例程,创建时,它将包含其子例程的环境打包。
子例程引用:
子例程并没有什么特别或神奇的地方,在这一节我们要学习如何创建对有名的和匿名的子例程的引用
对有名子例程的引用:
我们前面就已经讲过,要创建对现存变量的引用,只需给它加上反斜杠前缀。对于子例程也大致如此,
如&mysub 就是对&mysub的引用。又比如:
[root@master perl]# cat m12.pl
sub greet {
print “hello
”;
}
[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
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
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{printgreeting};
}
rs=gererate_greeting();
&rs();
[root@master perl]# perl m17.pl
hello world[root@master perl]#
sub{print $greeting} 这里是引用
让我们再来改动一下这段代码,以更好地理解闭包这个专业用语究竟能做什么:
闭包的应用;
闭包以两种似乎毫不相关的方式来应用,最常见的用法是用”智能” 回调子例程。
将闭包用作”智能”回调
由于闭包是一些包含少量私有数据的子例程引用,因为它们可以方便的应用在图形用户界面的回调过程中。
举例来说,你使用Tk工具包创建了一个按钮,并赋予它一个指向子例程的引用。当按钮被按下时将回调该子例程。
CreateButton 创建了一个GUI的按钮,并提供给它一个指向匿名子例程的引用($callback_proc),
它将依附于其环境中的my变量
闭包和对象的对比:
对象通俗的定义就是一组数据与函数的集合,数据提供对象函数操作的环境。比如,
$button->setForground(“yellow”)中,>setForground函数会自动知道你指的是哪个按钮。