scala成长之路(7)函数进阶——可能是史上最浅显易懂的闭包教程
由于scala中函数内部能定义函数,且函数能作为函数的返回值,那么问题来了,当返回的函数使用了外层函数的局部变量时,会发生什么呢?没错,就产生是闭包。
关于闭包的解释网上一大堆,但基本上都是照葫芦画瓢,一个模子刻出来的,说来说去都只讲了“内部函数引用外层函数的局部变量”这个刻板的定义,根本没降到精髓。精髓是什么?且看我一句话给你讲清楚:
闭包就是外层函数函数的对象,外层函数就是闭包的构造函数!
怎么样,是不是摸不着头脑?其实是这样,我们使用闭包的目的并不是为了引用外层函数的局部变量,这只是手段,不是目的;我们的最终目的其实是函数的定制化,即按照一定的模板根据输出生成具有不同功能的函数,其实就是“函数的函数”。这里我们马上可以想到,就相当于“类”的思想,能根据不同的构造函数产生不同的“类的对象”。其实这里就是利用了这种思路,把外层函数当做构造函数,利用传入的参数进行定制,生成具有不同功能的函数并返回。
道理我都懂,但这跟“引用局部变量”有什么关系?很简单呀,比方说外层函数就是一个毛坯房,返回的函数时精装修房,那么外层函数的参数是装修图纸,最终得到的房子肯定是要用到这个图纸或者图纸的衍生物的,因此为了实现定制化,很定要依靠于外层函数的局部变量。
但是这里有个问题:我们都知道,正常来说函数的局部变量是存储在栈内存的,而对象是存储在堆内存的,因此同一个类可能存在多个对象,而函数在执行完成之后栈内存就会释放,因此不会存在多份函数的局部变量。但是根据我们上边的分析,定制化的函数肯定是要用到局部变量的,而且不同的定制化肯定是要保存多份局部变量,且相互之间空间独立的,就如同不同的对象一样。那么scala是怎么解决这个问题的呢?根据这篇文章 https://www.jianshu.com/p/8f24150fad2a 的介绍,scala在生成闭包时使用了一个临时对象来保存外层函数中的局部变量,因此可以算是将当前堆内存中的变量拷贝了一份到栈内存中,因此实现了多份局部空间的并存,以及函数闭包。