區域變數與全域變數的比較
- 實作:區域變數編索引一個堆疊中的暫存器陣列,使用硬式編碼的整數索引(至少標準實作是這樣——LuaImplementations)。全域變數編索引則是從一個表格(或使用者資料)編索引,通常使用可變名稱字串,儲存為常數或變數,做為 key。
- 注意:在 5.2.0work3 中,全域變數概念仍存在程式語言中,但從 VM 中移除(無特殊的 GETGLOBAL/SETGLOBAL opcode)。從 VM 角度來看,全域變數與從區域(實際上是語法上層值)表格中存取/取得沒什麼不同。
- 注意:提升為上層值的區域變數在 VM 中的處理方式與一般的區域變數略有不同。上層值透過特殊的 VM opcode 存取。
- 語法:如果設定了環境表格,可以在 Lua 程式碼中存取全域變數,不論是否明確命名它們所來自的環境表格:
foo
、_G.foo
或 getfenv().foo
(或在 5.2.0work3 中,_ENV.foo
)。這允許不同的環境使用方式,例如 ModuleDefinition。
- 範圍:區域變數的範圍限定於一個語法區塊內。全域變數的範圍限定於執行期間指定給定環境表格的任意數量的函式內。在 5.2.0work3 中,全域變數的範圍限定於指定給定環境表格(在編譯期間宣告,但在執行期間指定)的任意數量的語法區塊內。
- 宣告:區域變數必須明確宣告,使用
local
陳述句,才能使用它們。預設為全域變數的指定並非 LocalByDefault。全域變數可以即時存取,即使執行期間設定變數名稱(例如,「foo=io.stdin:read'*l'; return _G[foo]
」)。區域變數的清單是靜態定義的。全域變數的清單可以在執行期間判定,甚至可以在程式執行期間變更。
- 標準函式庫存取:通常透過全域變數對一段程式碼公開標準函式庫。不過,另一種方式是明確傳遞 _G 或其元素做為區域參數,「
local _G, math, math_sqrt = ...
」,但這樣可能會花很多時間。
- 優先順序:局部變數覆寫全域變數。即使全域變數有更特定範圍也仍然適用,因此在 5.2.0work3 中,「
local x = 1; do local _ENV = {x=2}; return x end
」會傳回 1。
- 範圍傳遞:透過傳遞環境表,可以將一組完整的全域變數或對全域變數的參照傳遞到不同範圍。在 Lua 中,全域範圍在某種程度上是「一級閥值」。無法如此傳遞局部變數,除非建立一個包含明確定義引用項的封閉函數。唯 debug.getlocal/setlocal 是例外,如 StringInterpolation 中所使用,但這是一種權宜之計。
- 位元組碼內省:全域變數在位元組碼中較為明顯。全域取得/設定會變成包含指定變數名稱的 GETGLOBAL/SETGLOBAL opcode。在 5.2.0work3 中,這些會變成 GETTABUP/SETTABUP opcode [1]。可以 DetectingUndefinedVariables 所用方式列出已編譯區塊所讀取或寫入的位元組碼的所有全域變數。
- 數量限制:每個函數的局部變數數量有上限(MAXLOCALS,通常為 200)。
最近變更 · 喜好設定
編輯 · 記錄
最後編輯時間:2010 年 7 月 10 日下午 10:35 GMT (差異)