函数的声明格式
function add(a,b,c)
return a+b+c
end
多返回值
在lua中允许函数返回多个结果,返回方式形如return a,b
,其中a,b
参数不可用()
括住,否则会报错.
需要注意的是,lua会根据函数的被调用情况调整返回值的数量,如下情况
function test()
return 1,2
end
- 当函数被作为一条单独语句调用时,其所有返回值都会被丢弃
- 函数被作为表达式(例如,加法的操作数)调用时,将只保留第一位返回值,例如
>test()+1 -->2
只有当函数调用是一系列表达式中的最后一个表达式(或是唯一一个表达式)时,其所有的返回值才能被获取到.这里的一系列表达式
在lua中表现为4种情况:
- 多重赋值.
>a,b,c, d= test(), test() -->a=1,b=1, c=2 d=nil 这里的第一个test函数由于不是最后一个表达式,因此只有其第一个返回值被捕获并传递给了a参数
- 函数调用时传入的实参列表
> print(test(),'end') --> 1, "end"
> print('start', test()) --> "start", 1,2
- 表构造器.可以用此方法将所有返回值存入单个变量中
> t = {test()} --> t={1, 2}
> t= {test(), test()} --> t={1,1,2}
- return 语句.形如
return f()
的语句会返回f返回的所有结果
可变长函数参数
lua中使用...
表示可变长函数参数,例如
function test(...)
for _,v in pairs({...}) do
print(v)
end
end
获取可变长参数可以采用
a,b=...
的形式,其会将...
中的前两位保存到a b
变量中
可变长参数和固定参数是可以一起使用的,但是固定参数必须在函数参数的前面, 例如
function test(a,b,...)
end
要遍历...
参数,也可以使用table.pack
函数,该函数接收一个可变长参数,返回由该可变长参数组成的一个数组,并增加一个字段n
,代表该数组的长度,例如
function test(...)
local arg = table.pack(...)
print(arg.n)
print(arg[1])
print(arg[arg.n])
end
> test(1,2,3,4,5) --> 5 1 5
遍历...
参数还有一种方法,即使用select
函数,该函数总是具有一个固定参数selector
,以及数量可变的参数,如果selector
是数值n,那么select函数返回地n个参数(包含第n个)后的所有参数.selector
参数也可以是#
,表示返回参数的总数.
函数table.unpack
table.unpack
函数与table.pack
相反,其功能为将一个列表解包为一个边长参数,例如
a,b = table.unpack({1,2,3}) --> a=1,b=2
函数的尾调用
当一个函数的最后一个动作是调用另一个函数而没有在进行其他工作时,就形成了尾调用
.例如:
function f1() return f2() end
当f1函数调用完f2函数后即不再进行其他的任何操作,这样当f2
函数执行完成后,程序就不再需要返回最初的调用函数f1
.因此在尾调用之后,程序也就不需要在调用栈中保存有关调用函数的任何信息.当f2
函数返回时,程序的执行路径会直接回到调用f1
函数的位置.
这种在尾调用时不使用任何额外的栈空间,我们将这种实现称为尾调用消除
但是对于如下的一些用法并不是尾调用
-
function f1() f2() end
-- 此方式的函数,在f2
运行完后,还需要在f1
中丢弃f2
函数的返回值,因此不属于尾调用 -
return 1+f2()
-- 此方式在f2
运行完成后,还需要对其返回值做运算操作,也不属于尾调用 -
return x or f2()
-- 在f2
调用完成后还需要做判断,不属于尾调用 -
return (f2())
-- 强制将f2
函数返回值变为一个参数,不属于尾调用
在lua
语言中,只有形如return func(args)
的调用才是尾调用,但对于args
参数可以是任何复杂的表达式
网友评论