一 函数是第一类值的理解
0)和其它'常见类型'的值'数值、字符串'具有'同等权限'
1)将某个函数'保存到变量中'-->'全局、局部'变量
补充:它可以存储在"变量"或"table"里
2)函数'作为参数'传递给其他函数
补充:作为'实参'或'高阶函数'传递给其他函数调用
3)将某个函数作为'其它函数的返回值'返回
二 函数定义的等价方式
三 lua闭包
(1)闭包的由来
原因:lua中允许函数的'嵌套定义[define]',并且在'内嵌函数'中使用了'外包函数'中定义的'局部'变量
补充: C语言'static'有点这个'意味'
备注: c、'c#'就'不允许'函数的嵌套定义,但是'允许'函数的"嵌套调用(call)"
(2)函数嵌套定义
需求:将函数存储在'表字段' -->'匿名函数的味道'
(3)闭包的定义
'函数'可以访问他'被创建时'所处的'上下文环境',这被称为'闭包'
闭包:一个闭包就是'一个函数'外加能够'使该函数正确访问非局部变量'所需的其他'机制'
一个函数中'嵌套子函数',子函数可以'使用父函数中的局部变量',这种行为就是"闭包"
闭包 = 函数 + 引用环境
+++++++++++++++++"关键词"+++++++++++++++++
function、closure['闭包']、upvalue['非局部变量']、内嵌('inner')函数,外包('enclosing')函数
(4)闭包的几个概念
① upvalue
1. upvalue: "非局部"变量,"实际"指的是'变量'而'不是值'
备注:upvalue称该'内嵌函数'的'外部局部变量'(external local variable)
2. 理解为'C语言基础'函数内部定义的"静态(static)变量"
3. upvalue的"[定义]":一定是'外部函数'定义的的local'局部变量',且在'内部'函数'调用过'
++++++++++++++"更具体的描述"++++++++++++++
1) '外部函数'定义的'local'局部变量
2) 且在'内部函数中可以被调用'
++++++++++++++++'匿名函数访问一个非局部变量'++++++++++++++++
理解:站在'匿名函数'的角度中,count'既不是'全局变量'也不是'局部变量,而'是非局部变量'-->'upvalue'
② 词法定界
词法定界(lexical scoping):'内嵌函数'可以访问'外包函数'已经创建的'所有局部变量'
这种'特性[机制]'称之为'词法定界'
特性:一个函数A'内嵌套'另一个'函数B'的时候,'内函数B'可以访问'外部函数A'的'局部变量'
可以'访问'的原因: 内嵌与外包关系是'允许'传递的,架起一座'桥梁'
③ 闭包函数与一般函数的区别
1. 闭包只是在'形式和表现上'像函数,但实际上'不是函数'
2. 函数'只有一个实例',定义后'逻辑就确定了',不会执行时发生变化
④ 闭包的功能
⑤ 局部函数
'局部函数'可以理解为在'当前作用域有效的函数',可以用'local变量来引用'一个函数
'局部函数'对于'包'而言尤其重要
思考:局部函数的'作用域'?
++++++++++++++'应用场景'++++++++++++++
局部函数只能在'函数所在的文件中'引用;好处:可以'屏蔽细节'
⑥ 案例讲解
1)案例1
特殊: return '嵌套' return --> "返回"的是'局部函数'
补充:new_count()中传入的参数也是'局部变量',类似于在'外部函数内'定义一个'local变量'
核心点:当执行完'c1 = new_counter()'后,局部变量'count'的生命'本该'结束,但因为它已经成了内嵌函数c(它又被赋给了变量g1)的upvalue,所以它仍然能以'某种形式'继续"存活"下来
1. 内嵌函数定义在"count = count + 1"这条语句'之前'
2. upvalue实际是'local局部'变量-->"count",是保存在'函数堆栈框架'上(stack frame)的
3. 所以只要upvalue还'没有离开'自己的作用域,它就一直'生存'在"函数堆栈上"
4. 这种情况下,闭包将通过'指向'堆栈上的upvalue的引用来'访问'它们
5. 一旦upvalue'即将离开'自己的作用域(这也意味着它马上要从堆栈中消失),闭包就会为它'分配空间'并保存当前的值,以后便可通过'指向新分配空间的引用'来'访问'该upvalue
6. 当执行到c1的"count = count + 1"时,闭包已经'创建'了,但是count并'没有离开'作用域,所以闭包仍然'引用'堆栈上的count
7. 当'return count'完成时,count即将'结束'生命,此时闭包便将'count(已经是1了)'复制到自己'管理的空间'中以便将来访问
2)案例2
常见: 单层return,还是'返回局部函数'
3)案例3
upvalue通过'外层函数'传递 --> n
⑦ 应用场景
闭包:是数据和行为的"结合体",就好比'C++中的类',这样就使得闭包具有较好的'抽象能力'.
应用场景: 在某些场合下,我们需要'记住'某次调用完成以后'数据的状态' --> lua闭包能'完成'该功能.
备注:C语言的static类型的变量,每次'调用'完成以后,static类型的变量并'不会被清除'.
⑧ 参考链接
技术:Lua语言中'只有闭包而没有函数',函数本身只是'闭包的一种原型'
⑨ 小结
效果上: 按照C语言的'static'来理解;由于'upvalue'也是个局部变量,也只能在'作用域内'访问,这也是return的'局部函数'的原因