第一版是為 Lua 5.0 編寫的。儘管在很大程度上仍然適用於後續版本,但有一些區別。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買這本書,您還可以幫助 支持 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 會調整結果數量為一;因此,在最後一行,只有 "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。保留所有權利。 | ![]() |