Lua的函数
Lua的函数
前言:
最近在学些Lua的函数,之前学的太快导致有些概念性的东西记不住,这次把这些东西梳理下串起来。
1 Lua函数设计到的几个概念
问题:一些Lua书籍会这样介绍Lua中的函数,“Lua中的函数是带有词法定界的第一类值。你可能被里面的名词搞蒙了,我们看下这两个术语到底什么什么意思。
- 第一类值:我们都知道变量可以存储值,可以作为函数参数输入,可以作为函数返回值输出,可以存放在数组里,我们把这种特性称为第一类值。而Lua把函数也当作一种值来处理,在Lua你可以把函数当作值在变量中赋值传递,函数可以作为其他函数的参数(匿名函数比较喜欢这么用),可以作为函数的返回值输出(Lua实现闭包基础),可以存放在表中(Lua实现对象的基础)。因此我们说Lua的函数是第一类值。
- 词法定界:Lua函数可以嵌套定义。我们知道Lua的变量有两种,一种是定义在函数外部的全局变量,一种是定义在函数内部的局部变量。函数可以访问全局变量,但函数不能访问其他函数的局部变量,但有一种情况除外,就是内部嵌套定义的函数(注意这里说的是内部嵌套定义的函数,而不是内部调用的函数)可以访问外层函数的局部变量(upvalue),这种特性称为词法定界。不要把词法定界概念等同于闭包概念。
1 | function add1(a, b, c) |
运行输出结果为:7
这段代码演示了在add1函数内嵌套定义add2函数,add2函数本身参数为空,但直接调用了外部函数的局部变量。
- 闭包:Lua闭包可以说就是一个内部函数结合对upvalue变量的操作。Lua闭包结构特征明显,由两个函数构成,一个是内部函数自己,另一个是外部函数(称为工厂)。所以说Lua闭包并不是指某一种特殊的函数,而是我们所熟知的普通函数按照一定规则组合而成,函数之间存在某种特性(内部函数可访问外部函数局部变量,具有保存历史状态的特点)。
1 | function Test() |
运行输出结果为:
1 | fun1-- 1 1 1 |
这里在内部匿名函数里操作外部变量i,当一次调用结束后再次调用,i的值是在第一次调用的基础上累加,而外部函数里操作j和k值与之前是否调用过无关。也即闭包结构下内部函数使用外部函数的局部变量,具有记住历史状态的特性(这个特性可以设计迭代器)。虽然fun1和fun2的函数原型都是Test,但是他们有各自所操作的函数实例。fun1的调用次数与fun2调用次数互不影响。
继续看例子:
1 | function Test() |
运行输出结果为:
1 | fun1-- 1 1 |
这里例子里外部函数每次调用都会给k值赋值为1,而内部函数里进行累加1。从输出结果看出,k值的确是从1开始累加的,但在第一调用fun1创建k之后,闭包已经开始记住它的历史值了(有点类似c语言的static变量,但还是有本质区别),随后的调用累加都是在历史值基础上累加而不受外部函数赋值影响。假如你想在k累加到10之后不再累加,条件判断必须写在内部函数里,写在外部函数是无效的,外部函数只能决定k的最初历史值。
- 闭包在哪些方面使用
- 既然具有保留历史状态的特点当然适合用作迭代器。
- 同一个函数原型可以运行不同的函数实例,比如你有一个函数用迭代特性不断从一个状态推导出下一个状态(可能状态比较复杂,只能从历史状态推出下一个状态,不能像sin函数似的给x直接算y),然后原来的推导想继续,又期望开始一个新的推导,两个推导初始参数不同规则相同。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 OnlyCalm's Blog!
评论
ValineGitalk