闭包
1.什么是词法定界和闭包
当一个函数嵌套另一个函数定义时,内部函数可以访问外部的函数的局部变量,我们称之为词法定界 ,我们称这样的外部的局部变量(external local variable)或者 upvalue。
function newCounter()
local i = 0;
return function()
i = i + 1;
end
end
c1 = newCounter()
c2 = newCounter()
print(c1()) ---> 1
print(c1()) ---> 2
print(c2()) ---> 1
匿名函数 使用 upvalue i 保存了他的计数,当我们调用匿名函数的时候i已经超出了作用的返回,因为创建i的newCounter 已经返回了。然而Lua用闭包的思想正确处理了这种情况。简单的说闭包是一个函数加上它可以正确访问的Upvalues。
2.非全局函数
Lua中函数可以作为全局变量也可以作为局部变量,
作为全局变量的申明方式有3种:
lib = {}
lib.func1 = function(x,y) return x + y end
lib.func2 = function(x,y) return x - y end
Lib = {
func1 = function(x,y) return x + y end
func2 = function(x,y) return x - y end
}
Lib = {}
functioin Lib.func1 (x,y)
return x + y
end
functioin Lib.func2 (x,y)
return x + y
end
当我们用局部变量保存函数时,我们就得到一个局部函数,也就是说局部函数就像局部变量一样在一定的范围内有效。局部函数的申明方式有2种:
local f = function (x, y) return x + y end
local g = function (x, y) return f(x , y) end
local function f(...)
...
end
注意一点:在申明局部递归函数的时候 一定要先申明,否则会报错
local f = function(n)
if n < 0 then
return 1
end
return n*f(n-1) --------------buggy
上面的这段代码会有报错是因为Lua编译时遇到f(n-1)时它并不知道这个f是局部函数,Lua就回去查找是否有这样的全局函数f,为了解决这个问题 我们必须在定义之前申明这个函数:
local f
f = function(n)
if n < 0 then
return 1
end
return n*f(n-1) --------------buggy
3.正确的尾调用
尾调用是一种类似在函数结尾的goto调用,当函数最后一个动作是调用另外一个函数时,我们称之为尾调用
function f(x)
return g(x)
end
f调用g后不会再做任何事情,这种情况下当被调用函数g结束时程序不需要返回到调用者f;所以尾调用之后程序不会在栈中保留关于调用者的任何信息。一些编译器比如Lua编译器在利用这种特性处理尾调用时不使用额外的栈,我们称这种语言支持正确的尾调用。
由于尾调用不需要使用栈空间,所以尾调用的递归层次也是可以无限制的。