第一版是为 Lua 5.0 编写的。虽然在很大程度上仍然适用于较新版本,但有一些不同之处。
第四版针对 Lua 5.3,可在 Amazon 和其他书店购买。
购买本书,您还可以帮助 支持 Lua 项目。
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。保留所有权利。 |