scala成长之路(7)函数进阶——可能是史上最浅显易懂的闭包教程
由于scala中函数内部能定义函数,且函数能作为函数的返回值,那么问题来了,当返回的函数使用了外层函数的局部变量时,会发生什么呢?没错,就产生是闭包。
关于闭包的解释网上一大堆,但基本上都是照葫芦画瓢,一个模子刻出来的,说来说去都只讲了“内部函数引用外层函数的局部变量”这个刻板的定义,根本没降到精髓。精髓是什么?且看我一句话给你讲清楚:
闭包就是外层函数函数的对象,外层函数就是闭包的构造函数!
怎么样,是不是摸不着头脑?其实是这样,我们使用闭包的目的并不是为了引用外层函数的局部变量,这只是手段,不是目的;我们的最终目的其实是函数的定制化,即按照一定的模板根据输出生成具有不同功能的函数,其实就是“函数的函数”。这里我们马上可以想到,就相当于“类”的思想,能根据不同的构造函数产生不同的“类的对象”。其实这里就是利用了这种思路,把外层函数当做构造函数,利用传入的参数进行定制,生成具有不同功能的函数并返回。
道理我都懂,但这跟“引用局部变量”有什么关系?很简单呀,比方说外层函数就是一个毛坯房,返回的函数时精装修房,那么外层函数的参数是装修图纸,最终得到的房子肯定是要用到这个图纸或者图纸的衍生物的,因此为了实现定制化,很定要依靠于外层函数的局部变量。
但是这里有个问题:我们都知道,正常来说函数的局部变量是存储在栈内存的,而对象是存储在堆内存的,因此同一个类可能存在多个对象,而函数在执行完成之后栈内存就会释放,因此不会存在多份函数的局部变量。但是根据我们上边的分析,定制化的函数肯定是要用到局部变量的,而且不同的定制化肯定是要保存多份局部变量,且相互之间空间独立的,就如同不同的对象一样。那么scala是怎么解决这个问题的呢?根据这篇文章 https://www.jianshu.com/p/8f24150fad2a 的介绍,scala在生成闭包时使用了一个临时对象来保存外层函数中的局部变量,因此可以算是将当前堆内存中的变量拷贝了一份到栈内存中,因此实现了多份局部空间的并存,以及函数闭包。
scala成长之路(7)函数进阶——可能是史上最浅显易懂的闭包教程的更多相关文章
- python成长之路七-函数的进阶
1,python中,名称空间分三种: 全局命名空间 局部命名空间(临时命名空间) 内置名称空间 2,作用域(两种): 1,全局作用域 包含:全局名称空间 内置名称空间 2,局部作用域 包含:局 ...
- scala成长之路(6)函数入门
众所周知,scala作为一门极客型的函数式编程语言,支持的特性包括: 函数拥有“一等公民”身份: 支持匿名函数(函数字面量) 支持高阶函数 支持闭包 部分应用函数 柯里化 首先需要指出,在scala中 ...
- scala成长之路(5)问题记录
还是在看scala sdk源码的时候,有很多问题要考自己慢慢摸索,这里做个记录. 一. 隐式转换的作用域? 隐式转换需要三个因素 1. 己方(当前对象) 2. 转换函数 3. 对方(转换的目标类) 这 ...
- scala成长之路(4)compaion object——伴生对象的使用
虽然java一直声称自己是完全面向对象的语言,但一直以来都被很多人所质疑,其中java的静态成员函数就是主要的“罪魁祸首”.由于java中保留了静态方法的调用,导致其编程模式依然有过程式编程的可能,尤 ...
- scala成长之路(3)隐式转换
不废话,先上例子:定义一个参数类型为String的函数: scala> def sayHello(name:String) = println("hello " + name ...
- scala成长之路(2)对象和类
scala提供了一种特殊的定义单例的方法:object关键字 scala> object Shabi{ | val age = 0 | val name = "shabi" ...
- scala成长之路(1)基本语法和数据类型
scala作为JVM上的Lisp,是一种geek类型的编程语言,也一直是我等java程序员眼中的梦寐以求的一门技能,遂下定决心花一段时间好好学习scala.第一天学习,主要介绍与java在编程上的主要 ...
- python成长之路六-函数的初识
定义函数 我们现学已知的python函数有<内置函数> 而我们现在要学的是<自定义函数> 1,def 定义一个函数 def name(): # 后接函数名 冒号 pass 2 ...
- Python之路----生成器函数进阶
def generator(): print(123) yield 1 print(456) yield 2 g = generator() ret = g.__next__() print('*** ...
随机推荐
- QBC(Query By Criteria) QBE (Query By Example)
QBC 参考:(Hibernate的QBC查询) //is empty and is not empty @Test public void testQBC(){ Session session = ...
- sql server性能分析--执行sql次数和逻辑次数
目前在做一个项目优化时,想通过数据库层分析sql server系统性能,查了一下网上代码,修改了一下标题和DMVs代码,以下代码可以用来分析系统运行一段时间后,那些语句是系统忙的sql语句.做为参考. ...
- 排查在 Azure 中创建新 Linux 虚拟机时遇到的 Resource Manager 部署问题
本文内容 常见问题 收集活动日志 问题:自定义映像:预配错误 问题:自定义/库/应用商店映像:分配失败 后续步骤 尝试创建新的 Azure 虚拟机 (VM) 时,遇到的常见错误是预配失败或分配失败. ...
- HTTP Strict Transport Security
HTTP Strict Transport Security (通常简称为HSTS) 是一个安全功能,它告诉浏览器只能通过HTTPS访问当前资源, 禁止HTTP方式. 作用 一个网站接受一个HTTP的 ...
- SourceTree Win10 安装不成功解决过程记录
简介 SourceTree 是一款拥有可视化界面的项目版本控制软件,适用于git项目管理,同时它集成了 git flow 工作流程,对于不熟悉 git 命令的初学者来说,可以通过 SourceTree ...
- React学习笔记 - 元素渲染
React Learn Note 3 React学习笔记(三) 标签(空格分隔): React JavaScript 二.元素渲染 元素是构成react应用的最小单位. 元素是普通的对象. 元素是构成 ...
- javascript Object与Array用法
引用类型:引用类型是一种数据结构,用于将数据和功能组织在一起.引用类型的值是引用类型的一个实例. 一.Object ECMAScript中的对象其实就是一组数据和功能的结合. Object类型其实是所 ...
- python入门8 输入输出
输入 input() 输出 print() #coding:utf-8 #/usr/bin/python """ 2018-11-03 dinghanhua 输入输出 & ...
- IOS 应用管理(九宫格) 总结笔记
1. 开发前的思路 ========================================1> 从mainBundle中加载Plist2> 按照plist中的数据数量先确定各个a ...
- HTTP 状态码 301 302
301 Moved Permanently被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个URI之一.如果可能,拥有链接编辑功能的客户端应当自动把请求的地址修改为 ...