函数调用教程 |
|
由于 Lua 是动态类型的,并且不需要函数类型声明,因此检查函数所需的参数数量和类型似乎有些多余。Lua 能很好地处理调用参数和形参数量不匹配的情况。如果形参未被填满,它们将接收默认值 nil。如果传递了过多的参数,它们将被忽略。由于参数是动态类型的,因此不需要为每个参数指定类型。也就是说,我们只需要知道对象在使用时的类型,而不是在引用它时。我们将使用以下函数作为示例:
> function foo(a,b,c) print(a,b,c) end
> foo() nil nil nil
nil,或者没有值,而且我们没有收到错误。当我们传递过多参数时,会发生以下情况:> foo(1,2,3,4) 1 2 3
> foo("hello") hello nil nil > foo("pi", 3.1415, { comment="this is a table" }) pi 3.1415 table: 0x21d49b0
拥有可变数量的函数参数通常很有用。例如,C 语言中的 printf(format,...) 函数。Lua 处理此问题的一种方法是将可变参数列表放入一个名为 arg 的数组表中,该表可在函数内使用。例如:
> function foo(...) print(arg) end > foo("abc",3,77) table: 0x21d56a0
注意:在 Lua 5.2 中,arg 已弃用,取而代之的是三个点 (...),效果相似。
> function foo(...) print(...) end (In some cases, the argument list array must be referenced by placing the three periods within a set of curly braces.) > function foo(...) for k,v in pairs({...}) do print(k,v) end end
在此示例中,我们只能看到这是一个表。我们可以使用 table.foreach(table,function) 来打印可变参数表的值,但使用 pairs() 更好,因为 table.foreach() 在 Lua 5.1 中已弃用。
> function foo(...) for k,v in pairs(arg) do print(k,v) end end > foo() n 0
从一个空的可变参数列表可以看出,会额外添加一个表对来提供表中的元素数量,即 arg.n。在这种情况下,参数的数量为零。让我们尝试传递可变数量的参数:
> foo(1,2,3) 1 1 2 2 3 3 n 3 > foo("apple",2,"banana",99,3.1415927,foo) 1 apple 2 2 3 banana 4 99 5 3.1415927 6 function: 0x9ecd20 n 6
另一种方法是使用 ... 作为占位符:
> function foo(...) print('x', select(2, ...), 'y', ...) end > foo("apple", "banana", "orange") x banana y apple banana orange
... 还有一个额外的优势,即它避免了构建 arg 表所带来的微小性能损耗。
unpack() 是一个很有用的函数,用于处理可变参数。它接受一个表并返回一个变量列表,例如:
> = unpack({1,2,3})
1 2 3
这可以如下与可变参数列表一起使用:
> function listargs(...) >> return unpack(arg) >> end > = listargs({1,2,3}) 1 2 3 > = listargs({"hello", {1,2,3}, function (x) return x*x end}) hello table: 0x9efed0 function: 0x9eec40
它也可以如下用于将可变数量的参数传递给函数:
> function countargs(...) >> return #arg >> end > = countargs(1,2,3) 3 > = countargs(unpack{1,2,3}) 3
要理解 unpack 的工作原理,请看这个缓慢的伪代码实现:
> function unpack (t, i) >> i = i or 1 >> if t[i] ~= nil then >>> return t[i], unpack(t, i + 1) >> end > end
摘自 Lua 参考手册:[第 5.1 章 - 多重返回值]。
Lua 可以从函数返回多个值。这是通过返回一个逗号分隔的值列表来实现的:
> function foo(angle) >> return math.cos(angle), math.sin(angle) >> end > > print( foo(1) ) -- returns 2 values... 0.54030230586814 0.8414709848079 > > c,s = foo(3.142/3) -- assign the values to variables > = math.atan(s/c) 1.0473333333333 > = c,s 0.49988240461137 0.86609328686923 > > function many(x) >> return x, x*x, x*x*x, x*x*x*x, x*x*x*x*x >> end > = many(5) 5 25 125 625 3125 > = many(0.9) 0.9 0.81 0.729 0.6561 0.59049
上面的函数可以通过构造一个包含值的表并使用 unpack 来获得可变数量的返回值。例如:
> function many2(x,times) >> local t = {} >> for i=1,times do t[i] = x^i end >> return unpack(t) >> end > = many2(5,10) 5 25 125 625 3125 15625 78125 390625 1953125 9765625 > = many2(0.5,7) 0.5 0.25 0.125 0.0625 0.03125 0.015625 0.0078125
我们也可以将值作为表返回。为此,我们在函数调用周围加上花括号,这将构造一个表,即:
下面是一个使用之前函数示例的例子:
> = { foo(1.5) }
table: 0x204e100
> t = { foo(1.5) }
> for k,v in ipairs(t) do print(k,v) end
1 0.070737201667703
2 0.99749498660405
如果一个函数返回多个值,但我们只想获取第一个值,我们可以将函数调用括在括号中,即:
> = (foo(1.5)) 0.070737201667703 > = foo(1.5) 0.070737201667703 0.99749498660405
也可以通过返回一个表并取第一个元素来实现相同的功能,但上面的语法更有效率。例如:
> = ({foo(1.5)}) [1]
0.070737201667703