第一版為 Lua 5.0 所撰寫。儘管在後續版本中仍有很大的關聯性,但仍有一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買書籍,您也可以 贊助 Lua 專案。
![]() |
程式設計 Lua | ![]() |
第二部分。表格和物件 第 14 章。環境 |
Lua 中的全域變數不需要宣告。儘管這對小型程式很方便,但在大型程式中,一個簡單的拼寫錯誤可能會導致難以找到的錯誤。不過,如果我們願意,可以改變這種行為。由於 Lua 將其全域變數保存在常規表格中,因此我們可以使用元表格來改變其在存取全域變數時的行為。
第一種方法如下
setmetatable(_G, { __newindex = function (_, n) error("attempt to write to undeclared variable "..n, 2) end, __index = function (_, n) error("attempt to read undeclared variable "..n, 2) end, })在該程式碼之後,任何嘗試存取不存在的全域變數的行為都會觸發錯誤
> a = 1 stdin:1: attempt to write to undeclared variable a
但是,我們如何宣告新變數?使用 rawset
,它會繞過元方法
function declare (name, initval) rawset(_G, name, initval or false) end使用 or 搭配 false 可確保新的全域變數始終會取得與 nil 不同的值。請注意,您應該在安裝存取控制之前定義此函式,否則會出現錯誤:畢竟,您正在嘗試建立一個新的全域變數
declare
。有了這個函式,您就可以完全控制您的全域變數
> a = 1 stdin:1: attempt to write to undeclared variable a > declare"a" > a = 1 -- OK
但是現在,要測試變數是否存在,我們不能只將它與 nil 進行比較;如果它是 nil,存取會擲出錯誤。相反地,我們使用 rawget
,它會避免元方法
if rawget(_G, var) == nil then -- `var' is undeclared ... end
要將該控制變更為允許具有 nil 值的全域變數並不困難。我們只需要一個輔助表格來保留已宣告變數的名稱。每當呼叫元方法時,它就會在該表格中檢查變數是否未宣告。程式碼可能是這樣
local declaredNames = {} function declare (name, initval) rawset(_G, name, initval) declaredNames[name] = true end setmetatable(_G, { __newindex = function (t, n, v) if not declaredNames[n] then error("attempt to write to undeclared var. "..n, 2) else rawset(t, n, v) -- do the actual set end end, __index = function (_, n) if not declaredNames[n] then error("attempt to read undeclared var. "..n, 2) else return nil end end, })
對於這兩種解決方案,其負擔可以忽略不計。對於第一個解決方案,在正常運作期間永遠不會呼叫元方法。在第二個解決方案中,它們可能會被呼叫,但僅當程式存取包含 nil 的變數時。
版權所有 © 2003–2004 Roberto Ierusalimschy。保留所有權利。 | ![]() |