第一版是针对 Lua 5.0 编写的。虽然在很大程度上仍然适用于后续版本,但有一些差异。
第四版针对 Lua 5.3,可在 亚马逊 和其他书店购买。
购买本书,您还可以帮助支持 Lua 项目。
![]() |
Lua 中的编程 Lua | ![]() |
| 第一部分。语言 第 5 章。函数 |
Lua 的一个非常规但非常方便的功能是函数可以返回多个结果。Lua 中的几个预定义函数返回多个值。一个示例是 string.find 函数,它在字符串中查找模式。它返回两个索引:模式匹配开始的字符索引和模式匹配结束的字符索引(如果找不到模式,则返回 nil)。多重赋值允许程序获取两个结果
s, e = string.find("hello Lua users", "Lua")
print(s, e) --> 7 9
用 Lua 编写的函数也可以返回多个结果,方法是在 return 关键字后列出所有结果。例如,一个用于查找数组中最大元素的函数可以同时返回最大值及其位置
function maximum (a)
local mi = 1 -- maximum index
local m = a[mi] -- maximum value
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 始终根据调用的情况调整函数返回的结果数。当我们以语句的形式调用函数时,Lua 会丢弃其所有结果。当我们以表达式的形式使用调用时,Lua 仅保留第一个结果。只有当调用是表达式列表中的最后一个(或唯一)表达式时,我们才能获得所有结果。这些列表出现在 Lua 中的四个结构中:多重赋值、函数调用的参数、表构造函数和 return 语句。为了说明所有这些用法,我们将在以下示例中假设以下定义
function foo0 () end -- returns no results
function foo1 () return 'a' end -- returns 1 result
function foo2 () return 'a','b' end -- returns 2 results
在多重赋值中,函数调用作为最后一个(或唯一)表达式会生成与匹配变量所需的结果一样多的结果
x,y = foo2() -- x='a', y='b'
x = foo2() -- x='a', 'b' is discarded
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 is discarded
当函数调用是另一个调用的最后一个(或唯一)参数时,第一个调用的所有结果都作为参数。我们已经看到这种结构的示例,其中包含 print
print(foo0()) -->
print(foo1()) --> a
print(foo2()) --> a b
print(foo2(), 1) --> a 1
print(foo2() .. "x") --> ax (see below)
当对 foo2 的调用出现在表达式中时,Lua 会将结果数调整为 1;因此,在最后一行中,只有 "a" 用于连接。
print 函数可以接收可变数量的参数。(在下一节中,我们将看到如何编写具有可变数量参数的函数。)如果我们编写 f(g()) 并且 f 具有固定数量的参数,Lua 会将 g 的结果数调整为 f 的参数数,如我们之前所见。
构造函数还收集调用中的所有结果,没有任何调整
a = {foo0()} -- a = {} (an empty table)
a = {foo1()} -- a = {'a'}
a = {foo2()} -- a = {'a', 'b'}
与往常一样,这种行为仅在调用是列表中的最后一个调用时发生;否则,任何调用都只产生一个结果
a = {foo0(), foo2(), 4} -- a[1] = nil, a[2] = 'a', a[3] = 4
最后,像 return f() 这样的语句将返回 f 返回的所有值
function foo (i)
if i == 0 then return foo0()
elseif i == 1 then return foo1()
elseif i == 2 then return foo2()
end
end
print(foo(1)) --> a
print(foo(2)) --> a b
print(foo(0)) -- (no results)
print(foo(3)) -- (no results)
你可以通过将调用括在额外的圆括号对中来强制调用返回一个结果
print((foo0())) --> nil
print((foo1())) --> a
print((foo2())) --> a
请注意,return 语句不需要在返回值周围加上圆括号,因此放在那里的任何圆括号对都算作额外的圆括号对。也就是说,像 return (f()) 这样的语句总是返回一个单一值,无论 f 返回多少个值。也许这是你想要的,也许不是。
具有多个返回值的特殊函数是 unpack。它接收一个数组,并从索引 1 开始将数组中的所有元素作为结果返回
print(unpack{10,20,30}) --> 10 20 30
a,b = unpack{10,20,30} -- a=10, b=20, 30 is discarded
unpack 的一个重要用途是在通用调用机制中。通用调用机制允许你动态地调用任何函数,并带有任何参数。例如,在 ANSI C 中,没有办法做到这一点。你可以声明一个接收可变数量参数的函数(使用 stdarg.h),并且可以使用指向函数的指针来调用可变函数。但是,你不能使用可变数量的参数调用函数:你在 C 中编写的每个调用都有一个固定数量的参数,并且每个参数都有一个固定的类型。在 Lua 中,如果你想使用数组 a 中的可变参数调用可变函数 f,你只需编写
f(unpack(a))对
unpack 的调用将返回 a 中的所有值,这些值将成为 f 的参数。例如,如果我们执行
f = string.find
a = {"hello", "ll"}
那么调用 f(unpack(a)) 将返回 3 和 4,与静态调用 string.find("hello", "ll") 完全相同。
虽然预定义的 unpack 是用 C 编写的,但我们也可以使用递归在 Lua 中编写它
function unpack (t, i)
i = i or 1
if t[i] ~= nil then
return t[i], unpack(t, i + 1)
end
end
我们第一次调用它时,带有一个参数,i 获得 1。然后函数返回 t[1],后跟 unpack(t, 2) 的所有结果,而后者又返回 t[2],后跟 unpack(t, 3) 的所有结果,依此类推,直到最后一个非 nil 元素。
| 版权所有 © 2003–2004 Roberto Ierusalimschy。保留所有权利。 | ![]() |