闭包

  • lua中的函数都可以认为是闭包,只不过为了便于理解还是用了函数的概念。
  • lua中函数的返回值可以是匿名函数,也就是闭包。以下面的代码为例,提出一个概念:非局部的变量。在下面的代码中,匿名函数访问了一个变量i,它对于newCount来说是局部变量,对于匿名函数来说是既不是局部变量也不是全局变量,在lua中这个称谓非局部的变量。
  • 在lua中一个闭包指的是一个函数和该函数所需要访问的非局部的变量。lua会把它们看做是一个整体,因此在下面的代码中多次允许c1和c2,会发现变量i是在递增的。这是因为c1 = newCount()这句代码相当于给c1赋值了一个闭包,它包含了i这个变量。因此多次执行相当于就是在反复执行一个对象,这样i就一直是原来那个i。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function ()
local i =0
return function ()
i=i+1
print(i)
end
end

c1 = newCount()
print(c1())
print(c1())

c2 = newCount()
print(c2())
print(c2())
print(c1())


1
2
1
2
3

闭包的沙盒

  • 下面这段代码中,修改了math库的sin方法。类似的还可以用来处理一些不安全的代码,这样的方式类似沙盒,将不安全包装了起来。
    1
    2
    3
    4
    5
    6
    7
    8
    print(math.sin(45))

    oldSin = math.sin
    math.sin = function (x)
    return oldSin(x*math.pi/180)
    end

    print(math.sin(45))

递归

直接使用非全局的函数递归会报错,如下代码,会报:attempt to call global 'foo' (a nil value)这个是因为在调用foo(x-1)时,这个foo函数还没有定义完,因此表达式在尝试调用一个全局的函数foo,但是显然这个全局函数是不存在的。

1
2
3
4
5
6
7
8
local foo = function (x)
if x == 1 then
return 1
else return x*foo(x-1)
end
end

print(foo(3))

正确写法

local foo
fool = function(x)
    if x == 1 then
        return 1
    else
        return x*foo(x-1)    
    end
end
-- 相当于
local function foo(x)    

正确的尾调用本质是为了不记录函数的返回位置,这样在栈中就可以无限的调用函数。在lua中只有return ()这样的形式才是尾调用。