Lua学习笔记(5)——深入函数

1.函数是一种“第一类值”,他们具有特定的词法域。

2.第一类值,表示Lua中函数与其他类型的值(例如数字)具有相同的权利,函数可以存储到变量或table中,也可以作为实参,还可以作为其他函数的返回值。

3.词法域,是指一个函数可以嵌套在另一个函数中,内部函数可以访问外部函数的变量。

4.函数与其他值一样都是匿名的。即,一个函数名(如print)是一个持有某函数的变量,与其他变量持有各种值的道理是一样的。

Lua学习笔记(5)——深入函数_第1张图片
函数是匿名的

5.function foo(x) return 2*x end 只是所谓的“语法糖”,是 foo = function(x) return 2*x end 的简化书写形式。此时,表达式“funcrion(x) end”相当于函数的构造式,结果为一个“匿名函数”。

Lua学习笔记(5)——深入函数_第2张图片
匿名函数

6.接受另一个函数作为实参的函数(例如sort),称为“高阶函数(higher-order function)”。高阶函数是一种强大的编程机制,应用匿名函数来创建高阶函数所需的实参则可以带来更大的灵活性。

闭合函数(closure)

假设有一个学生姓名的表和一个对应名称的年级表
Lua学习笔记(5)——深入函数_第3张图片
根据学生的年级来对姓名排序

1.上例中,传递给sort的匿名函数可以访问参数grades,而grades是外部函数sortbygrade的局部变量(参数也是一种局部变量)。在这个匿名函数内部,grades既不是全局变量也不是局部变量,将其称为一个“非局部的变量(non-local variable 或 upvalue)”。

2.一个闭合函数就是一个函数加上该函数所需访问的所有“非局部的变量”。从技术上来说,Lua中只有闭合函数,因为函数本身就是一种特殊的closure(即没有非局部变量的closure)。

3.closure结构通常涉及两个函数:closure本身和用于创建该closure的工厂函数。

4.closure对于回调函数很有用。

Lua学习笔记(5)——深入函数_第4张图片
colsure在回调中的使用

5.closure还可用于重新定义某些函数。

重新定义sin
Lua学习笔记(5)——深入函数_第5张图片
将老版sin存到私有变量后,只有通过新版本的sin才能访问它

6.利用closure创建沙盒(sandbox),即一个安全的运行环境。

Lua学习笔记(5)——深入函数_第6张图片
限制程序访问文件(经过重新定义后,程序只能通过受限版本的os.open函数来调用原有的函数,通过将不安全的版本保存到closure的一个私有变量中,从而使得外部再也无法直接访问到原来的版本)

非全局函数(non-global function)

1.只要将一个函数存储到一个局部变量中,即得到了一个“局部函数”,也就是说该函数只能在某个特定的作用域中使用。

Lua学习笔记(5)——深入函数_第7张图片
词法域确保程序包中的其他函数可以使用局部函数

2.对于局部函数的定义,Lua还支持一种特殊的“语法糖”:

局部函数定义
上述语法糖展开

3.在定义递归的局部函数时,需要特别注意:

Lua学习笔记(5)——深入函数_第8张图片
递归中的局部函数
Lua学习笔记(5)——深入函数_第9张图片
上述递归函数的简化

4.间接递归中,必须使用一个明确的前向声明(forward declaration):

Lua学习笔记(5)——深入函数_第10张图片
间接递归

正确的尾调用(proper tail call)

1.尾调用(tail call),一个函数调用是另一个函数的最后一个调用动作,该调用就称为“尾调用”。判断一个调用是不是尾调用的准则是“一个函数在调用完另一个函数之后,是否就无事可做”。即“return ()”这样的调用形式。

对g的调用就是尾调用
f调用完g之后还需丢弃g的返回值,所以不算尾调用
不是尾调用
在调用前会对参数求值,所以它们可以是任意复杂的表达式

2.尾调用消除(tail-call elimination),尾调用后,函数就无事可做了,因此程序就不需要保存任何关于该函数的栈信息,执行控制权在g返回时,直接返回到f中调用的点上。这使得在进行尾调用时不耗费任何栈空间。

3.由于尾调用不耗费栈空间,所以一个程序可以拥有无数嵌套的尾调用: 

n为任何数字时,都不会造成栈溢出

4.尾调用的一大应用就是编写“状态机”。

5.举一个简单的迷宫游戏例子:一个迷宫有几间房间,每个房间中有东南西北4扇门,用户在每一步移动中都需输入一个移动的方向。如果某个方向上有门,那么用户可以进入对应的房间,不然,程序就打印一条警告。游戏的目标是让用户从最初的房间走到最终的房间。

Lua学习笔记(5)——深入函数_第11张图片
当前房间就是一个状态,将每间房间都实现为一个函数,并使用尾调用来实现从一间房间移动到另一间房间。使用尾调用对用户的移动次数没有任何限制。

你可能感兴趣的:(Lua学习笔记(5)——深入函数)