闭包的介绍 闭包是一种编程理念,支持将函数当成对象使用的编程语言,一般都支持闭包,比如Python, JavaScript。
在维基百科上,对闭包有如下定义:
在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。
用通俗一点的话来说,就是函数中嵌套了另一个函数(称为内部函数),这个内部函数使用了外部函数的参数、以及函数中定义的变量,并且内部函数被当成对象返回,这样就形成了闭包。
闭包的形成条件 通过闭包的介绍,我们可以得知闭包的形成条件:
存在函数嵌套(函数里面再定义函数)
内部函数使用了外部函数的变量(还包括外部函数的参数)
外部函数返回了内部函数
闭包的示例 下面使用Python写一个简单的闭包示例。需求是这样的:有一个数据保存的业务,保存的介质可能是文件,也可能是数据库等其他方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 41 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 30 import java.util.function.Consumer;public class FunctionalExample { public static void main (String[] args) { Consumer <String> saveToHdfs = new Consumer <String>() { private int num = 0 ; @Override public void accept (String content) { System.out.println("数据保存至【HDFS】,保存内容为:" + content); num++; System.out.println("今日已保存数据条数:" + num); } }; saveToHdfs.accept("一条订单记录" ); saveToHdfs.accept("个人信息变更" ); } }