资料摘自<Lua程序设计(第二版)>
函数
在Lua中,函数是一种对语句和表达式进行抽象的主要机制。
function add(a)
local sum=0
for i,v in ipairs(a) do
sum = sum + v
end
return sum
end
一个函数定义具有一个名称(本例中的add)、一系列的参数(参数表)和一个函数体(即一系列的语句)。
"形式参数(parameter)"的使用方式与局部变量非常相似,它们由调用函数时的"实际参数(argument)"初始化的。调用函数时提供的实参可以与形参数量不同。Lua会自动调整实参的数量,以匹配参数表的要求。这项调整与多重赋值很相似,即"若实参多于形参,则舍弃多余的实参;若实参不足,则多余的形参初始化为nil"。如:
function f(a,b) return a or b end
调用 形参
f(3) a = 3,b= nil
f(3,4) a=2,b=4
f(3,4,5) a=3,b=4(5被丢弃了)
多重返回值
Lua具有一项非常与众不同的特征,允许函数返回多个结果。Lua的几个预定义函数就是返回多个值的。例如,用于在字符串中定位一个模式的函数string.find。例如,用于在字符串中定位一个模式的函数string.find。该函数若在字符串中找到了指定的模式,将返回匹配的起始字符和结尾字符的索引。在此就需要使用多重赋值语句来接收函数的返回值。
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
Lua会调整一个函数的返回值数量以适应不同的调用情况:
function foo0() end --无返回值
function foo1() return "a" end --返回1个结果
function foo2() return "a","b" end --返回2个结果
若一个函数是最后的(或仅有的)一个表达式,那么Lua会保留其尽可能多的返回值:
x,y = foo2() --x="a",y="b"
x = foo2() --x="a","b"被丢弃
x,y,z = 10,foo2() --x=10,y="a",z="b"
如果一个函数没有返回值或者没有返回足够的返回值,那么Lua会用nil来补充缺失的值:
x,y = foo0() --x=nil,y=nil
x,y = foo1() --x="a",y=nil
x,y,z = foo2() --x="a",y="b",z=nil
如果一个函数调用不是一系列表达式的最后一个元素,那么将只产生一个值:
x,y = foo2(),20 --x="a",y=20
x,y = foo0(),20,30 --x=nil,y=20,30被丢弃
当一个函数调用作为另一个函数调用的最后一个(或仅有的)实参时,第一个函数的所有返回值都将作为实参传入第二个函数:
print(foo0()) -->
print(foo1()) -->a
print(foo2()) -->a b
print(foo2(),1) -->a 1
print(foo2().."x") -->ax
也可以将一个函数调用放入一对圆括号中,从而迫使它只返回一个结果:
print((foo0())) -->nil
print((foo1())) -->a
print((foo2())) -->a
变长参数
下面函数返回了所有参数的总和:
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个点(...)表示该函数可接受不同数量的实参。当这个函数被调用时,它的所有参数都会被收集到一起。这部分收集起来的实参称为这个函数的"变长参数"。
function fwrite(fmt,...)
return io.write(string.format(fmt,...))
end
注意在3个点前有一个固定参数fmt。具有变长参数的函数同样也拥有任意数量的固定参数,但固定参数必须放在变长参数之前。Lua会将前面的实参赋予固定参数,而将余下实参视为变长参数。如:
fwrite() fmt=nil,没有变长参数
fwrite("a") fmt="a",没有变长参数
fwrite("%d%d",4,5) fmt="%d%d",变长参数=4和5
下面演示如何使用select来遍历一个函数的所有变长参数:
for i=1,select('#',...) do
local arg = select(i,...) --得到第i个参数
<循环体>
end
selcet("#",...)会返回所有变长参数的总数,其中包括nil。
具名实参
Lua中的参数传递机制是具有"位置性"的,也就是说在调用一个函数时,实参是通过在参数表中的位置与形参匹配起来的。第一个实参的值与第一个形参相匹配,依此类推。
但有时候你可能会要求通过名称来指定实参,使用os.rename来修改文件名称,通常你会忘记第一个参数是表示新文件还是旧文件,因此希望这个函数能接受两个具有名称的实参,如:
--无效的演示代码
rename(old="temp.lua",new="temp1.lua")
Lua并不直接支持这种语法,但可以通过一种细微的改变来获得相同的效果。
arg={old="temp.lua",new="temp1.lua"}
function rename(arg)
return os.rename(arg.old,arg.new)
end