资料摘自<Lua程序设计(第二版)>
深入函数
在Lua中,函数是一种"第一类值",这表示Lua中的函数与其他传统类型的值(例如数字和字符串)具有相同的权利。函数可以存储到变量或table中,可以作为实参传递给其他函数,还可以作为其他函数的返回值。
当谈论一个函数名称时(例如print)实际上是在讨论一个持有某函数的变量。
function foo(x) return 2*x end
其实是以下代码的一种简化书写形式:
foo = function (x) return 2*x end
因此一个函数定义实际就是一条赋值语句,这条语句创建了一种类型为"function"的值,并将这个值赋予一个变量。
创建一个安全的运行环境,即所谓的"沙盒"。当执行一些未受信任的代码时就需要一个安全的运行环境,例如在服务器中执行那些从internet上接收到的代码。举例来说,如果要限制一个程序访问文件的话,只需使用closure来重定义函数io.open就可以了。
do
local oldOpen = io.open
local access_OK = function(filename,mode)
<检查访问权限>
end
io.open = function(filename,mode)
if access_OK(filename,mode)
return oldOpen(filename,mode)
else
return nil,"access denied"
end
end
end
这个示例的精彩之处在于,经过重新定义后,一个程序就只能通过新的受限版本来调用原来那个未受限的open函数了。示例将原来不安全的版本保存到closure的一个私有变量中,从而使得外部再无法直接访问到原来的版本了。
由于函数是一种"第一类值",因此一个显而易见的推论就是,函数不仅可以存储在全局变量中,还可以存储在table字段中和局部变量中。
前面讲到了几个将函数存储在table字段中的示例,大部分Lua库也采用了这种机制。若要在Lua中创建这种函数,只需将常规的函数语法与table语法结合起来使用即可:
Lib={}
Lib.foo = function(x,y) return x+y end
Lib.goo = function(x,y) return x-y end
在定义递归的局部函数时,还有一个特别之处需要注意。
local fact = function (n)
if n == 0 then
return 1
else
return n*fact(n-1) --错误
end
end
当Lua编译到函数体中调用fact(n-1)的地方时,由于局部的fact尚未定义完毕,因此这句表达式其实是调用了一个全局的fact,而非此函数自身。可这样解决这个问题:
local fact
fact = function (n)
if n == 0 then
return 1
else
return n*fact(n-1) --错误
end
end
现在函数中的fact调用就表示了局部变量。即使在函数定义时这个变量的值尚未完成定义,但之后在函数执行时fact则肯定已经拥有了正确的值。