第一版是针对 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。保留所有权利。 |