闭包的介绍
闭包是一种编程理念,支持将函数当成对象使用的编程语言,一般都支持闭包,比如Python, JavaScript。
在维基百科上,对闭包有如下定义:
在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。
用通俗一点的话来说,就是函数中嵌套了另一个函数(称为内部函数),这个内部函数使用了外部函数的参数、以及函数中定义的变量,并且内部函数被当成对象返回,这样就形成了闭包。
闭包的形成条件
通过闭包的介绍,我们可以得知闭包的形成条件:
- 存在函数嵌套(函数里面再定义函数)
- 内部函数使用了外部函数的变量(还包括外部函数的参数)
- 外部函数返回了内部函数
闭包的示例
下面使用Python写一个简单的闭包示例。需求是这样的:有一个数据保存的业务,保存的介质可能是文件,也可能是数据库等其他方式。1
2
3
4
5
6
7
8
9
10
11
12
13
14
def save_data(type):
num = 0
def wapper(content):
print(str.format("数据保存至【{target}】,保存内容为:{content}",target=type,content=content))
nonlocal num
num += 1
print(str.format("今日已保存数据条数:{0}" ,num))
return wapper
save_to_database = save_data("数据库")
save_to_database("一条订单记录")
save_to_database("个人信息变更")
执行上面脚本结果如下:1
2
3
4数据保存至【数据库】,保存内容为:一条订单记录
今日已保存数据条数:1
数据保存至【数据库】,保存内容为:个人信息变更
今日已保存数据条数:2
闭包的作用
通过上面的简单示例,容易看出闭包的一个优点是复用性,普通的函数调用完就会释放资源了,但使用闭包的情况下,将一个函数的功能蕴含在一个对象中,这个对象通常不会被回收,也就是将函数的逻辑功持久化到了内存中,后续可以多次复用该函数逻辑。
扩展:Java中的闭包
Java是面向对象编程的,所以不存在函数嵌套的这种情况,但Java的类是可以嵌套的,可以用类的嵌套来实现类似的思想。
下面是用Java实现前文中保存数据的例子。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* @author liaosi
*/
public class SaveData {
private String target;
private InnerClass innerClass;
private int num = 0;
public SaveData(String target) {
this.target = target;
this.innerClass = new InnerClass();
}
private class InnerClass {
public void saveContent(String content) {
System.out.println("数据保存至【" + target + "】,保存内容为:" + content);
num++;
System.out.println("今日已保存数据条数:" + num);
}
}
public void save(String content) {
innerClass.saveContent(content);
}
public static void main(String[] args) {
SaveData saveToDatabase = new SaveData("数据库");
saveToDatabase.save("一条订单记录");
saveToDatabase.save("个人信息变更");
}
}
在 Java8 中,引入了 lambda 表达式和函数式接口,函数式接口只有一个方法,意味着一个接口只用来实现一个单一的功能,这样的接口就有点像函数的意味了。前面讲到,闭包的思想是把一个逻辑功能封装到对象里,所以我们可以创建一个函数式接口的实例,将接口的功能封装在对象里,我理解这也算是在Java中闭包思想的一种实现方式。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.util.function.Consumer;
/**
* @author liaosi
*/
public class FunctionalExample {
public static void main(String[] args) {
Consumer<String> saveToHdfs = new Consumer<String>() {
private int num = 0;
public void accept(String content) {
System.out.println("数据保存至【HDFS】,保存内容为:" + content);
num++;
System.out.println("今日已保存数据条数:" + num);
}
};
saveToHdfs.accept("一条订单记录");
saveToHdfs.accept("个人信息变更");
}
}