您的位置:首页 > 其它

[点点搬家]关于闭包(closure)的小知识

2015-01-06 17:28 218 查看
[两年前的博客,那时候对于java里没有的东西充满了好奇]

先说数学意义把,很简单。

闭合:如果一个集合中的数据对于一个运算后还处于这个集合中,则该集合对于该运算闭合。如实数对减法和加法都闭合,但是自然数则不然。

闭包:如果某个集合S对一个运算不闭合,通常可以找到包含这个S的最好闭合集合,则这个闭合集合叫做集合S对于这个运算的闭包。还如同上面的例子,自然数的集合{1,2,3,4,5,6,7,8,9}对于减法的闭包应该是{-8,-7.....7,8} (如果我没算错的话……)

行,数学上就不深究了,没啥意义,看程序的吧。

程序上来说,闭包的意义在于一个代码块可以包含自由变量——因为自由变量被包含在代码块中了,丫就不能被释放了。

不同语言对闭包的支持程度不一样,用perl来举例,perl用匿名subroutine来实现闭包:

sub generate_greeting {
my($greeting) = "hello world";
return sub {print $greeting};
}
$rs = generate_greeting();
&$rs(); # Prints "hello world"

上面代码中$greeting是lexcial的(用my修饰,必须用my),且属于那个匿名代码块,所以这个变量就释放不鸟了。想让闭包这个功能有意义,把hello world替换掉,变成一个输入的变量:

sub generate_greeting {
my($greeting) = @_;     # $greeting primed by arguments
return sub {
my($subject)= @_;
print "$greeting $subject \n";
};
}
$rs1 = generate_greeting("hello");
$rs2 = generate_greeting("my fair");

# $rs1 and $rs2 are two subroutines holding on to different $greeting's
&$rs1 ("world") ;  # prints "hello world"
&$rs2 ("lady") ;   # prints "my fair lady"

鸟然了吧,在perl里,闭包就是这么用地。

那该问了,在perl里用闭包意义何在?如上述代码,可以用generate_greeting($arg1,$arg2)代替,为啥用闭包呢?其实仔细思考一下,两个还是有细微差别的,回归闭包本质,$rs1与$rs2是包含了自己持有的变量的,而generate_greeting("hello","world")与generate_greeting("my fair", "lady")只是一个模板,没有任何数据。这是两者的一个区别,既然我在比包中有了数据,就能增加一些有趣的功能,下面我们继续修改这段代码:

use strict;
use warnings;
use 5.010;

sub generate_greeting {
my($greeting) = @_;     # $greeting primed by arguments
return sub {
my($subject)= @_;
$greeting .= '~';
print "$greeting $subject \n";
};
}

my $rs1 = generate_greeting("hello");
my $rs2 = generate_greeting("my fair");

for(1..10){
&$rs1 ("world") ;
&$rs2 ("lady") ;
}

输出为:

hello~ world
my fair~ lady
hello~~ world
my fair~~ lady
hello~~~ world
my fair~~~ lady
hello~~~~ world
my fair~~~~ lady
hello~~~~~ world
my fair~~~~~ lady
hello~~~~~~ world
my fair~~~~~~ lady
hello~~~~~~~ world
my fair~~~~~~~ lady
hello~~~~~~~~ world
my fair~~~~~~~~ lady
hello~~~~~~~~~ world
my fair~~~~~~~~~ lady
hello~~~~~~~~~~ world
my fair~~~~~~~~~~ lady

可以看到,拥有了数据就相当于拥有了状态,而不再是单一的一个输入对应唯一一个输出的机制了,这个特性是对立于纯函数的。

closure的一个应用就是grep函数:

my @evenList = grep {$_ % 2 == 0} (1..10);

这里就传递了一个闭包进去,是一种十分泛化的做法。

再如,更加常见的地方就是异步调用,利用闭包来填补事件驱动程序与顺序程序之间的沟壑。虽然用sub直接当callback既可以了,如果利用带闭包的callback就可以更加的smart,后续代码未来再补充
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  closure perl