第一版是為 Lua 5.0 編寫的。儘管在很大程度上仍然適用於後續版本,但仍有一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買本書,您還可以協助 支援 Lua 專案。
![]() |
使用 Lua 進行程式設計 | ![]() |
第 2 部分。表格和物件 第 15 章。套件 |
建立套件的所有這些方法有一個缺點,就是它們需要程式設計人員特別注意。例如,很容易忘記在宣告中使用 local。全域變數表格中的元方法提供了一些有趣的替代技術來建立套件。所有這些技術的共同點是使用套件的獨佔環境。這很容易做到:如果我們變更套件主區塊的環境,它建立的所有函式都將共用這個新環境。
最簡單的技術只做這些事。一旦套件擁有獨佔環境,不僅所有函式共用這個表格,所有全域變數也會進入這個表格。因此,我們可以將所有公開函式宣告為全域變數,它們將自動進入一個獨立的表格。套件只需要將這個表格註冊為套件名稱即可。下列程式碼片段說明了這個技術在 complex
函式庫中的應用
local P = {} complex = P setfenv(1, P)現在,當我們宣告函式
add
時,它會進入 complex.add
function add (c1, c2) return new(c1.r + c2.r, c1.i + c2.i) end此外,我們可以呼叫這個套件中的其他函式,而不需要任何前置詞。例如,
add
從其環境中取得 new
,也就是說,它取得 complex.new
。
這個方法提供對套件的良好支援,程式設計人員只需做一點額外的工作。它完全不需要前置詞。呼叫已匯出的函式和私人函式之間沒有差異。如果程式設計人員忘記使用 local
,她不會污染全域命名空間;相反地,只有一個私人函式會變成公開函式。此外,我們可以將它與前一節中套件名稱的技術一起使用
local P = {} -- package if _REQUIREDNAME == nil then complex = P else _G[_REQUIREDNAME] = P end setfenv(1, P)
當然,缺少的是存取其他套件。一旦我們將空表格 P
設為我們的環境,我們就會失去存取所有先前全域變數的權限。有幾個解決方案可以解決這個問題,每個解決方案都有其優缺點。
最簡單的解決方案是繼承,如我們先前所見
local P = {} -- package setmetatable(P, {__index = _G}) setfenv(1, P)(在呼叫
setfenv
之前必須呼叫 setmetatable
;你能告訴我原因嗎?)有了這個結構,套件就能直接存取任何全域識別碼,但每次存取都要付出一些小額的開銷。這個解決方案有一個有趣的結果,在概念上,你的套件現在包含所有全域變數。例如,使用你的套件的人可能會呼叫標準正弦函數,寫成 complex.math.sin(x)
。(Perl 的套件系統也有這個特殊性。)
存取其他套件的另一個快速方法是宣告一個包含舊環境的區域變數
local P = {} pack = P local _G = _G setfenv(1, P)現在你必須在任何存取外部名稱之前加上
_G.
,但你會得到更快的存取,因為沒有涉及元方法。與繼承不同,這個方法讓你對舊環境有寫入存取權;這好不好見仁見智,但有時你可能需要這種彈性。
一種更嚴謹的方法是只宣告你需要的函數為區域變數,或最多宣告你需要的套件為區域變數
local P = {} pack = P -- Import Section: -- declare everything this package needs from outside local sqrt = math.sqrt local io = io -- no more external access after this point setfenv(1, P)這個技巧需要更多工作,但它能更好地記錄你的套件依賴關係。它也會產生比前一個方案更快的程式碼。
版權所有 © 2003–2004 Roberto Ierusalimschy。保留所有權利。 | ![]() |