在lua中,函数是一种对语句和表达式进行抽象的主要机制。函数既可以完成某项特定

的任务,也可以只做一些计算并返回结果;

lua为面向对象式的调用也提供了一种特殊语法——冒号操作符。表达式o.foo(o,x)的

另一种写法是o:foo(x),冒号操作符使调用o.foo时将o隐含地作为函数的第一个参数;

一个lua程序既可以使用lua编写的函数,又可以调用以C语言编写的函数。

所有lua标准程序库中的函数都是用C语言写的;

函数中形式参数的使用方式与局部变量相似,它们是由调用函数时的实际参数初始化

的。调用函数时提供的实参数量可以与形参数量不同,lua会自动调整实参的数量以

匹配参数表的要求,即"若实参多于形参,则舍弃多余的实参;若实参不足,则多余

的形参初始化为nil";但这种行为可能会导致一些编程错误,尽量不要去这么做;

 

5.1多重返回值

lua具有一项非常与众不同的特征,即允许函数返回多个结果,只需在return关键字

后列出所有的返回值即可;

lua也会调整一个函数的返回值数量以适应不同的调用情况;

只有当一个函数调用时一系列表达式中的最后一个元素时,才能获得它的所有返回值;

这里的“一系列表达式”表现为4中情况:多重赋值,函数调用时传入的实参列表,table

的构造式 和 return语句;

在多重赋值中:

如果一个函数调用时最后一个表达式,那么lua会保留其尽可能多的返回值,用于

匹配赋值变量;

如果一个函数没有返回值或者没有足够多的返回值,那么lua会用nil来补充缺失的值;

如果一个函数调用不是一系列表达式的最后一个元素,那么只将产生一个值;

如果一个函数调用作为另一个函数调用的最后一个实参时,第一个函数的所有返回值

都将作为实参传入第二个函数,若第一个函数出现在一个表达式中时,lua会将其返回

值数量调整为1;例子 ——> print(foo2() .."x")

 

table构造式可以完整地接收一个函数调用的所有结果,即不会有数量方面的调整;

不过这种行为只有当函数调用作为table的最后一个元素时才会发生,而在其他位置

上的函数调用总是只产生一个结果值;

如果一个函数调用时作为return语句的最后一个元素时会返回它的所有结果;

可以将一个函数调用放入一对圆括号中迫使它只返回一个结果;

 

一个特殊的函数 —— unpack,它接受一个数组作为参数,并从下标1开始返回该数组的所有

元素;unpack的一项重要用途体现在“泛型调用--genericcall”机制中;

泛型调用机制可以动态地以任何实参来调用任何函数;如果想调用任意函数f,而所有的参数

都在数组a中,那么可以这么写:

f(unpack(a))
unpack  将返回a中所有的值,这些值将作为函数f的实参。
unpack的lua实现(通过递归):
function unpack(t, i)
    i = i or 1
    if t[i] then 
        returnt[i], unpack(t, i+1)
end
end

 

5.2变长参数

lua函数可以接受不同数量的实参;例如:

function add(...)
local s = 0
    for i, v inipairs{...} do 
        s = s + v
    end
return s

end

参数表中的3个点(...)表示函数可接受不同数量的实参。当函数被调用时,它的所有参数会被收集到一起,

称为这个函数的"变长参数";

一个函数要访问它的参数时仍需要3个点(...),此时这3个点是作为一个表达式来使用的。

表达式"..."的行为类似于一个具有多重返回值的函数,它返回的是当前函数的所有变长参数;

例如: local a, b, c = ...

具有变长参数的函数同样也可以拥有任意数量的固定参数,但固定参数必须放在变长参数之前。

遍历一个函数的变长参数时只需要使用表达式{...},这就像访问一个table一样;

但在某些特殊情况下,变长参数会包含一些故意传入的nil,那么此时就需要用函数select来访问变长参数了。

调用select时,必须传入一个固定实参selector(选择开关) 和 一系列变长参数。如果selector为数字n,那么它

返回它的第n个可变实参;否则,selector只能为字符串"#",这样select会返回变长参数的总数,其中包括nil;

例如:

for i=1, select("#", ...) do

    local arg =select(i, ...)

    <循环体>

end

了解Lua5.0 与 Lua5.1 关于变长参数的不同!

 

5.3具名实参

Lua的参数传递机制是具有位置性的,也就是说在调用一个函数时实参是通过它在参数表中的位置与形参

匹配起来的。但有时通过名称来指定实参也是很有用的。具体做法:将所有实参组织到一个table中,

并将这个table作为唯一的实参传给函数。如:

function rename(arg)

    returnos.rename(arg.old,arg.new)

end

函数rename的参数改为只接受一个table类型的参数;在调用rename时,要注意Lua中特殊的函数调用语法,

就是当实参只有一个table构造式时,函数调用中的圆括号是可有可无的:

 rename{old = "temp.lua", new ="temp1.lua"}