--第六章 深入理解函数
Lua中函数是“第一类值”,与其他传统类型有相同的权利:
可以储存到变量或table中,可以作为函数实参传递,还可以作为函数的返回值。
函数的标准定义:
foo = function(x) return x*2 end
一个函数定义实际上就是一条赋值语句,这条语句创建了一种类型为“函数”的值,并将这个值赋予一个变量。
--6.1closure(闭合函数)
function newCounter() local i = 0 return function() i = i + 1 return i end end
非局部的变量(non-local variable):
是外部函数的局部变量,在内部的匿名函数中,既不是局部也不是全局变量。如上面的i。
一个closure就是一个函数加上该函数所需访问的所有“非局部的变量”。
c1和c2是同一个函数创建的两个不同的closure,它们各自拥有局部变量i的独立实例。
c1 = newCounter() print(c1()) -->1 print(c1()) -->2 c2 = newCounter() print(c2()) -->1 print(c1()) -->3 print(c2()) -->2
--6.2非全局函数
一个错误的示例:
local fact = function(n) if n == 0 then return 1 else return n * fact(n-1) end end
当编译到函数体中调用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调用就表示局部变量。
使用语法糖
local function foo() <body> end
Lua将其展开为:
local foo foo = function() <body> end
因此使用语法糖可以直接定义递归:
local function fact(n) if n == 0 then return 1 else return n*fact(n-1) end end
但是对于间接递归,必须使用明确的前向声明(forward declaration)
local f,g function g() ... f() ... end function f() ... g() ... end
--6.3正确的尾调用(tail call)
当一个函数调用的是另一个函数的最后动作是,才是一条尾调用:
function f(x) return g(x) end
不是尾调用的示例:
function f(x) g(x) end --调用完g后,f并不能立即返回,而还需要丢弃g返回的临时结果 return g(x) + 1 --还要做一个加法 return x or g(x) --还要调整为一个返回值 return (g(x)) --还要调整为一个返回值
一个尾调用就好比一个goto语句,迷宫游戏的案例:
function room1() local move = io.read() if move == "south" then return room3() elseif move == "east" then return room2() else print("invalid move") return room1() end end function room2() local move = io.read() if move == "south" then return room4() elseif move == "west" then return room1() else print("invalid move") return room2() end end function room3() local move = io.read() if move == "north" then return room1() elseif move == "east" then return room4() else print("invalid move") return room3() end end function room4() print("congratulations!") end
通过调用room1()进入游戏
时间: 2024-10-17 22:05:34