在Lua中,函数是一种对语句和表达式进行抽象的主要机制。函数既可以完成某项特定的任务,也可以只做一些计算并返回结果。
Lua具有一项非常于总不同的特征,允许函数返回多个结果:
s, e = string.find("Hello Lua users", "Lua") print(s, e) -->7 9
以Lua编写的函数同样可以返回多个结果,只需在return关键字后列出所有返回值即可:
function maximum (a) local mi = 1 --最大值的索引 local m = a[mi] --最大值 for i, val in ipairs(a) do if val > m then mi = i; m = val end end return m, mi end print(maximum({8, 10, 23, 12, 5}) -->23 3
关于多重返回值还要介绍一个特殊函数--unpack。它接受一个数组作为参数,并从下标1开始返回该数组的所有元素:
print(unpack{1, 2, 3}) -->1 2 3 a, b = unpack{1, 2, 3} -->a=1, b=2, 3被丢弃
Lua中的函数还可以接受不同数量的实参:
function add(...) local s = 0 for i, v in ipairs{...} do s = s + v end return s end print(add(3, 4, 10, 25, 12)) -->54
参数表中的3个点(...)表示该函数可接受不同数量的实参。实际上,还可以通过变长参数来模拟Lua中普通的参数传递机制,例如:
function foo(a, b, c) --可以转换为: function foo(...) local a, b, c = ... end
Lua提供了专门用于格式化文本(string.format)和输出文本(io.write)的函数。很自然地会想到将这两个函数合二为一:
function fwrite(fmt, ...) return io.write(string.format(fmt, ...)) end
--调用 参数 fwrite() fmt = nil,没有变长参数 fwrite("a") fmt = "a",没有变长参数 fwrite("%d%d", 4, 5) fmt = "%d%d",变长参数为4和5
在Lua中,函数是一种“第一类值”,这表示在Lua中函数与其他传统类型的值具有相同的权利。函数可以存储到变量中或table中,可以作为实参传递给其他函数,还可以作为其他函数的返回值。
在Lua中有一个容易混淆的概念是,函数与所有其他值一样都是匿名的,即它们都没有名称。当讨论一个函数名是(例如print),实际上是在讨论一个持有某函数的变量。
a = {p = print} a.p("Hello World") -->Hello World print = math.sin --'print'现在引用了正弦函数 a.p(print(1)) -->0.841470 sin = a.p --'sin'现在引用了print函数 sin(10, 20) -->10 20
“词法域”是指一个函数可以嵌套在另一个函数中,内部的函数可以访问外部函数中的变量。
function newCounter() local i = 0 return function() --匿名函数 i = i + 1 return i end end c1 = newCounter() print(c1()) -->1 print(c1()) -->2
在这段代码中,匿名函数访问了一个“非局部的变量”i,调用i 时并没有超出作用范围。一个closure(闭合函数)就是一个函数加上该函数所需访问的所有“非局部的变量”。如果再次调用newCounter,那么它会创建一个新的局部变量i,从而也将得到一个新的closure:
c2 = newCounter() print(c2()) -->1 print(c1()) -->3 print(c2()) -->2
将函数储存在table中:
Lib = { foo = function(x, y) return x+y end, goo = function(x, y) return x-y end }
Lib = {} function Lib.foo(x, y) return x+y end function Lib.goo(x, y) return x-y end
将函数储存在局部变量中:
local fact fact = function(n) if n == 0 then return 1 else return n*fact(n-1) end end -- local fact = function(n) ....... --用这种方式定义递归是错误的,因为调用fact(n-1)时,局部的 --fact尚未定义完毕
当一个函数调用时另一个函数的最后一个动作时,该调用称为“尾调用”,“尾调用”不会耗费栈空间(“尾调用消除”)。
function f(x) return g(x) end
return x[i].foo(x[j]+a*b, i+j)
以下调用都不符合尾调用准则(一个函数在调用完另一个函数之后,是否就无其他事情需要做了):
return g(x)+1 --必须做一次加法 return x or g(x) --必须调整为一个返回值 return (g(x)) --必须调整为一个返回值
function func(...) local mytable = {...} for k, v in pairs(mytable) do print(k, v) end end func("123", 12, "ok") -->1 123 -->2 12 -->3 ok