第一版是为 Lua 5.0 编写的。虽然在很大程度上仍然适用于更高版本,但有一些差异。
第四版针对 Lua 5.3,可在 Amazon 和其他书店购买。
购买这本书,您还可以帮助支持 Lua 项目。
用 Lua 编程 | ||
第二部分。表和对象 第 14 章。环境 |
通常,赋值足以获取和设置全局变量。但是,我们经常需要某种形式的元编程,例如当我们需要操作一个全局变量时,其名称存储在另一个变量中,或者在运行时以某种方式计算出来。为了获取此变量的值,许多程序员会忍不住编写类似以下内容的东西
loadstring("value = " .. varname)()或
value = loadstring("return " .. varname)()例如,如果
varname
是 x
,则连接将产生 "return x"
(或 "value = x"
,使用第一种形式),在运行时将实现所需的结果。但是,此类代码涉及创建和编译新块以及大量额外工作。您可以使用以下代码实现相同的效果,其效率比前一种方法高一个数量级以上
value = _G[varname]因为环境是一个常规表,所以您可以简单地使用所需的键(变量名)对其进行索引。
以类似的方式,您可以将值分配给动态计算的全局变量,编写 _G[varname] = value
。但请注意:一些程序员对这些函数有点兴奋,最终编写了类似 _G["a"] = _G["var1"]
的代码,这只是编写 a = var1
的一种复杂方式。
前一个问题的概括是允许动态名称中的字段,例如 "io.read"
或 "a.b.c.d"
。我们使用循环解决此问题,该循环从 _G
开始,逐个字段演化
function getfield (f) local v = _G -- start with the table of globals for w in string.gfind(f, "[%w_]+") do v = v[w] end return v end我们依赖于
string
库中的 gfind
来迭代 f
中的所有单词(其中“单词”是一系列一个或多个字母数字字符和下划线)。
用于设置字段的相应函数稍微复杂一些。像这样的赋值
a.b.c.d.e = v与以下完全等效
local temp = a.b.c.d temp.e = v也就是说,我们必须检索到最后一个名称;我们必须单独处理最后一个字段。新的
setfield
函数还会在路径中创建中间表(如果它们不存在)。
function setfield (f, v) local t = _G -- start with the table of globals for w, d in string.gfind(f, "([%w_]+)(.?)") do if d == "." then -- not last field? t[w] = t[w] or {} -- create table if absent t = t[w] -- get the table else -- last field t[w] = v -- do the assignment end end end此新模式在变量
w
中捕获字段名称,并在变量 d
中捕获可选的后续点。如果字段名称后面没有点,则它是最后一个名称。(我们将在 第 20 章 中详细讨论模式匹配。)
使用前面的函数,调用
setfield("t.x.y", 10)将创建一个全局表
t
、另一个表 t.x
,并将 10 分配给 t.x.y
print(t.x.y) --> 10 print(getfield("t.x.y")) --> 10
版权所有 © 2003–2004 Roberto Ierusalimschy。保留所有权利。 |