第一版是为 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。保留所有权利。 |