此第一版是針對 Lua 5.0 編寫的。雖然在很大程度上仍然適用於後續版本,但仍有一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買此書,您同時也能支持 Lua 專案


15.5 – 其他功能

正如我先前所述,使用表格來實作套件讓我們得以使用 Lua 的所有功能來操作它們。可能性是無限的。以下我僅提供一些建議。

我們不需要同時定義套件的所有公開項目。例如,我們可以在一個獨立的區塊中,將一個新項目新增到我們的 complex 套件

    function complex.div (c1, c2)
      return complex.mul(c1, complex.inv(c2))
    end
(但請注意,私有部分僅限於一個檔案,我認為這是一件好事。) 相反地,我們可以在同一個檔案中定義多個套件。我們只需要將每個套件封裝在一個 do 區塊中,讓它的區域變數僅限於該區塊。

在套件外部,如果我們要經常使用某些操作,我們可以為它們提供區域名稱

    local add, i = complex.add, complex.i
    
    c1 = add(complex.new(10, 20), i)
或者,如果我們不想一直撰寫套件名稱,我們可以為套件本身提供一個較短的區域名稱
    local C = complex
    c1 = C.add(C.new(10, 20), C.i)

撰寫一個函式來解開套件,將其所有名稱放入全域命名空間中,這很容易

    function openpackage (ns)
      for n,v in pairs(ns) do _G[n] = v end
    end
    
    openpackage(complex)
    c1 = mul(new(10, 20), i)
如果您在開啟套件時擔心名稱衝突,您可以在指派之前檢查名稱
    function openpackage (ns)
      for n,v in pairs(ns) do
        if _G[n] ~= nil then
          error("name clash: " .. n .. " is already defined")
        end
        _G[n] = v
      end
    end

由於套件本身是表格,我們甚至可以巢狀套件;也就是說,我們可以在一個套件中建立另一個套件。然而,這種功能很少有必要。

另一個有趣的設施是自動載入,它只會在程式實際使用函式時載入函式。當我們載入一個自動載入套件時,它會建立一個空表格來表示套件,並設定表格的 __index 元方法來執行自動載入。然後,當我們呼叫任何尚未載入的函式時,會呼叫 __index 元方法來載入它。後續呼叫會發現函式已載入;因此,它們不會啟用元方法。

實作自動載入的一個簡單方法如下。每個函式都在一個輔助檔案中定義。(每個檔案中可以有多個函式。) 其中每個檔案都以標準方式定義其函式,例如像這裡

    function pack1.foo ()
      ...
    end
    
    function pack1.goo ()
      ...
    end
然而,檔案不會建立套件,因為在載入函式時套件已存在。

在主套件中,我們定義一個輔助表格,用來描述我們可以在哪裡找到每個函式

    local location = {
      foo = "/usr/local/lua/lib/pack1_1.lua",
      goo = "/usr/local/lua/lib/pack1_1.lua",
      foo1 = "/usr/local/lua/lib/pack1_2.lua",
      goo1 = "/usr/local/lua/lib/pack1_3.lua",
    }
然後我們建立套件並定義其元方法
    pack1 = {}
    
    setmetatable(pack1, {__index = function (t, funcname)
      local file = location[funcname]
      if not file then
        error("package pack1 does not define " .. funcname)
      end
      assert(loadfile(file))()     -- load and run definition
      return t[funcname]           -- return the function
    end})
    
    return pack1
載入這個套件後,程式第一次執行 pack1.foo() 時,它會呼叫 __index 元方法,這很簡單。它會檢查函式是否有對應的檔案,並載入該檔案。唯一需要注意的是,它不僅必須載入檔案,還必須將函式作為存取的結果傳回。

由於整個系統都是用 Lua 撰寫的,因此很容易改變其行為。例如,函式可以用 C 定義,元方法使用 loadlib 載入它們。或者我們可以在全域表格中設定一個元方法,以自動載入整個套件。可能性是無窮無盡的。