Lua語言將全局環境自身保存在全局變量_G中,如下輸出全局環境中所有全局變量的名稱:
for n in pairs(_G) do print(n) end
- 具有動態名稱的全局變量
全局變量在另一個變量中的獲取,
value = load("return"..varname)() 和
value = _G[varname] 相同效果,後者效率高出一個數量級。
- 全局變量聲明
全局變量不需聲明就可以使用,檢測所有全局表不存在的訪問,如下:
setmetatable(_G,{
__newindex = function (_,n)
error("attempt to write to undeclared varibale "..n,2)
end,
__index = function (_,n)
error("attempt to read to undeclared varibale "..n,2)
end,
})
當然可以使用rawset,rawget繞過元方法。
- 非全局變量
自由名稱(free name)如:x 等價於 _ENV.x,_ENV本身是一個局部變量,是任意表,稱爲一個環境。
Lua處理全局變量的方式:
編譯所有代碼前,在外層創建局部變量_ENV;
所有自由名稱var變換爲_ENV.var;
函數load使用全局環境初始化代碼段的第一個上值,即lua語法內部維護的一個表。
- 使用_ENV
代碼段(一個文件)都有一個_ENV變量。_ENV = nil 會使後續代碼不能直接訪問全局變量。_ENV主要用途是改變代碼段使用的環境。使用繼承把舊環境裝入如下:
local newgt = {}
setmetatable(newgt, {__index = _G})
_ENV = newget
任何賦值都發生在新表中。只能通過_G來修改全局變量中的變量。
- 環境和模塊
_ENV解決污染全局變量。
- _EVN和load
load通常把加載代碼段上值_ENV初始化爲全局環境,還有一個可選參數爲_ENV指定不同初始值。
env = {}
loadfile("config.lua","t",env)()
類似運行在沙盒中。
重複運行一段代碼數次,每次不同環境,兩種選擇如下:
第一種使用debug.setupvalue(f,1,env)
第一個參數是指定函數,第二參數是上值索引(永遠是1),第三參數是新上值。【依賴調試庫,打破可見性規則】
另一種,每次加載代碼段對其修改,如下:
lua把所有代碼段當做可變長參數函數進行編譯,多出來這一行會把傳給代碼段的第一個參數賦值給_ENV,從而改變環境。
prefix = "_ENV = ...;"
f = loadwithprefix(prefix,io.lines(filename,"*L"))
...
env1 = {}
f(env1)
env2 = {}
f(env2)