此第一版是針對 Lua 5.0 編寫的。雖然在後續版本中仍有很大的相關性,但有一些差異。
第四版針對 Lua 5.3,可在 Amazon 和其他書店購買。
購買書籍,您也可以幫助支援 Lua 專案。
![]() |
用 Lua 程式設計 | ![]() |
第二部分。表格和物件 第 14 章。環境 |
環境的問題之一在於它是全域的。您對其所做的任何修改都會影響程式的所有部分。例如,當您安裝元表來控制全域存取時,整個程式都必須遵循準則。如果您想要使用未宣告全域變數的函式庫,您就倒楣了。
Lua 5.0 透過允許每個函式擁有自己的環境來改善此問題。這乍聽之下可能很奇怪;畢竟,全域變數表的目標是要成為全域的。然而,在第 15.4 節中,我們將看到此功能允許多種有趣的建構,其中全域值仍可在任何地方使用。
您可以使用 setfenv
函式(設定函式環境)來變更函式的環境。它接收函式和新環境。除了函式本身之外,您也可以提供一個數字,表示給定堆疊層級中的活動函式。數字 1 表示目前的函式,數字 2 表示呼叫目前函式的函式(這對於撰寫變更其呼叫者環境的輔助函式很方便),依此類推。
第一次嘗試使用 setfenv
會慘不忍睹。程式碼
a = 1 -- create a global variable -- change current environment to a new empty table setfenv(1, {}) print(a)會產生
stdin:5: attempt to call global `print' (a nil value)(您必須在單一區塊中執行該程式碼。如果您在互動模式中逐行輸入,每一行都是不同的函式,而對
setfenv
的呼叫只會影響其自己的行。)一旦您變更環境,所有全域存取都將使用此新表格。如果它為空,您就失去了所有全域變數,甚至是 _G
。因此,您應該先使用一些有用的值來填充它,例如舊環境
a = 1 -- create a global variable -- change current environment setfenv(1, {_G = _G}) _G.print(a) --> nil _G.print(_G.a) --> 1現在,當您存取「全域」
_G
時,它的值是舊環境,其中您會找到欄位 print
。
您也可以使用繼承來填充新環境
a = 1 local newgt = {} -- create new environment setmetatable(newgt, {__index = _G}) setfenv(1, newgt) -- set it print(a) --> 1在此程式碼中,新環境從舊環境繼承
print
和 a
。不過,任何指定都會傳遞到新表格。不會有誤改真正全域變數的危險,儘管您仍可透過 _G
來變更它們
-- continuing previous code a = 10 print(a) --> 10 print(_G.a) --> 1 _G.a = 20 print(_G.a) --> 20
當您建立一個新函數時,它會從建立它的函數繼承其環境。因此,如果一個區塊改變它自己的環境,它之後定義的所有函數都會共享這個相同的環境。這是建立命名空間的一個有用的機制,正如我們將在下一章看到的。
版權所有 © 2003–2004 Roberto Ierusalimschy。保留所有權利。 | ![]() |