Lua学习笔记:函数深入

闭包

  • 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 newCount()
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是个local的,怎么会提示是global呢?这个是因为在调用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 function foo(x)其实是第一个方法的语法糖。
1
2
3
4
5
6
7
8
9
10
11
12
13
local foo
foo = function (x)
if x == 1 then
return 1
else return x*foo(x-1)
end
end

print(foo(3))

-- 相当于
local function foo(x)
...

正确的尾调用

  • 本质是为了不记录函数的返回位置,这样在栈中就可以无限的调用函数。在lua中只有return <func>(<args>)这样的形式才是尾调用。
# Lua
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×