第一版是為 Lua 5.0 編寫的。儘管在很大程度上仍然適用於後續版本,但有一些區別。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買這本書,您還可以幫助 支持 Lua 項目


5.1 – 多個結果

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 元素。