闭包 (closure)是个精确但又很难解释的电脑名词。在 Perl 里面,闭包是以匿名函数的形式来实现,具有持续参照位於该函数范围之外的文字式变数值的能力。这些外部的文字变数会神奇地保留它们在闭包函数最初定义时的值 (深连结)。
本文节选自:http://www.overk.com/feature/teach/prel/perlfaq7.html#_closure_O_H
如果一个程式语言容许函数递回另一个函数的话 (像 Perl 就是),闭包便具有意义。要注意的是,有些语言虽提供匿名函数的功能,但却无法正确处理闭包; Python 这个语言便是一例。如果要想多了解闭包的话,建议你去找本功能性程式设计的教科书来看。Scheme这个语言不仅支援闭包,更鼓励多加使用。
以下是个典型的产生函数的函数:
sub add_function_generator { return sub { shift + shift }; }
$add_sub = add_function_generator(); $sum = &$add_sub(4,5); # $sum现在是 9了
闭包用起来就像是个 函数样板,其中保留了一些可以在稍後再填入的空格。 add_function_generator()
所递回的匿名函数在技术上来讲并不能算是一个闭包,因为它没有用到任何位在这个函数范围之外的文字变数。
把上面这个例子和下面这个 make_adder()
函数对照一下,下面这个函数所递回的匿名函数中使用了一个外部的文字变数。这种指名外部函数的作法需要由 Perl递回一个适当的闭包,因此那个文字变数在匿名函数产生之时的值便永久地被锁进闭 包里。
sub make_adder { my $addpiece = shift; return sub { shift + $addpiece }; }
$f1 = make_adder(20); $f2 = make_adder(555);
这样一来 &$f1($n)
永远会是 20加上你传进去的值 $n
,而 &$f2($n)
将 永远会是 555加上你传进去的值 $n
。$addpiece的值会在闭包中保留下来。
闭包在比较实际的场合中也常用得到,譬如当你想把一些程式码传入一个函数时:
my $line; timeout( 30, sub { $line = <STDIN> } );
如果要执行的程式码当初是以字串的形式传入的话,即 '$line = <STDIN>'
,那麽 timeout()
这个假想的函数在回到该函数被呼叫时所在的范围後便无法再撷取 $list
这个文字变数的值了。