曲径通幽论坛

标题: 闭包 [打印本页]

作者: beyes    时间: 2011-10-28 14:46
标题: 闭包
闭包是指“一个带有数据(attitude)的匿名子例程(匿名子函数),也可以称作”inside-out objects"。

对象是附有子例程的数据,而闭包则是附带有一些数据的子例程。

在 Perl 中,对象简单的说就是一个散列表,而散列表正是一些数据,而操作一个对象则需要用它所从属的包(类)中的方法进行,而这些方法实际就是一些子例程。

下面代码演示了一个简单的闭包:
[code=perl]#!/usr/bin/perl


my $name = "Jasmine";


{     # 闭包
        my $name = "King";
        my $age  = 25;


        $ref = sub { return "$name is $age. \n"; }
}
print "$name is back\n";
print &{$ref};[/mw_shl_code]
运行输出:
$ ./exp1.pl
Jasmine is back
King is 25.
第 1 句输出中的 $name 就是外围的 Jasmine ,这点是显而易见的。
程序中,$ref 是一个匿名子例程的指针,&{$ref} 这种方式是通过指针来调用子例程。注意,在闭包内有两个 my 变量($name 和 $age)。在非闭包的使用情况下,在代码块(花括号之外)外是看不到这两个变量的,然而在闭包的使用方式中,即使是在代码块外调用,该子例程(匿名子例程,即闭包)也能访问这两个变量。之所以外部能访问闭包内的词法变量,正是因为 $ref 这个引用要访问它们,除非不再引用这些变量,否则 Perl 不会清除它们的。如果你在 $ref 前面也用一个 my 来声明,那么引用也就会出错了。从这里可以看出,$ref 就像是一根通往闭包内的探针。

再考虑下面的一个例子:
[code=perl]#!/usr/bin/perl


sub paint {
        my $color = shift;


        my $ref = sub {
                my $object = shift;
                print "Paint the $object $color.\n";
        };
        return $ref;
}


my $p1 = paint("red");
my $p2 = paint("blue");


$p1->("flower");
$p2->("sky");[/mw_shl_code]
运行输出:
$ ./exp2.pl
Paint the flower red.
Paint the sky blue.
在上面程序中,分别以不同的参数调用了同一个 paint() 子例程,每次调用时,Perl 都会为其创建一个新的词法变量 $color ,并赋予该变量独立的值。变量 $color 会包含在返回的那个闭包中。指针 $p1 和 $p2 指向的是匿名子例程的引用,它们各自形成一个“闭包”,其中分别含有在 paint() 中定义的变量 $color,并可以各自访问该变量在本闭包中的副本,直到变量不再被引用为止。




欢迎光临 曲径通幽论坛 (http://www.groad.net/bbs/) Powered by Discuz! X3.2