第一版针对 Lua 5.0 编写。虽然在很大程度上仍然适用于后续版本,但存在一些差异。
第四版针对 Lua 5.3,可在 亚马逊 和其他书店购买。
购买本书,您还可以帮助支持 Lua 项目。
用 Lua 编程 | ||
第二部分。表和对象 第 12 章。数据文件和持久性 |
要处理具有通用拓扑结构(即,带有循环和共享子表的)的表,我们需要采用不同的方法。构造函数无法表示此类表,因此我们不会使用它们。要表示循环,我们需要名称,因此我们的下一个函数将获取要保存的值及其名称作为参数。此外,我们必须跟踪已保存表的名称,以便在检测到循环时重用它们。我们将使用一个额外的表进行此跟踪。此表将把表作为索引,并将它们的名称作为关联值。
我们将保留一个限制,即我们想要保存的表仅具有字符串或数字作为键。以下函数序列化这些基本类型,返回结果
function basicSerialize (o) if type(o) == "number" then return tostring(o) else -- assume it is a string return string.format("%q", o) end end下一个函数完成艰巨的工作。
saved
参数是跟踪已保存表的表
function save (name, value, saved) saved = saved or {} -- initial value io.write(name, " = ") if type(value) == "number" or type(value) == "string" then io.write(basicSerialize(value), "\n") elseif type(value) == "table" then if saved[value] then -- value already saved? io.write(saved[value], "\n") -- use its previous name else saved[value] = name -- save name for next time io.write("{}\n") -- create a new table for k,v in pairs(value) do -- save its fields local fieldname = string.format("%s[%s]", name, basicSerialize(k)) save(fieldname, v, saved) end end else error("cannot save a " .. type(value)) end end例如,如果我们构建一个类似于
a = {x=1, y=2; {3,4,5}} a[2] = a -- cycle a.z = a[1] -- shared sub-table的表,则调用
save('a', a)
将按如下方式保存它
a = {} a[1] = {} a[1][1] = 3 a[1][2] = 4 a[1][3] = 5 a[2] = a a["y"] = 2 a["x"] = 1 a["z"] = a[1](这些赋值的实际顺序可能有所不同,因为它取决于表遍历。不过,该算法确保在新的定义中需要的任何先前的节点都已定义。)
如果我们想要保存具有共享部分的多个值,我们可以使用相同的 saved
表对 save
进行调用。例如,如果我们创建以下两个表
a = {{"one", "two"}, 3} b = {k = a[1]}并按如下方式保存它们
save('a', a) save('b', b)结果将没有公共部分
a = {} a[1] = {} a[1][1] = "one" a[1][2] = "two" a[2] = 3 b = {} b["k"] = {} b["k"][1] = "one" b["k"][2] = "two"但是,如果我们对每次对
save
的调用使用相同的 saved
表
local t = {} save('a', a, t) save('b', b, t)那么结果将共享公共部分
a = {} a[1] = {} a[1][1] = "one" a[1][2] = "two" a[2] = 3 b = {} b["k"] = a[1]
与 Lua 中通常的情况一样,还有其他几种选择。其中,我们可以保存一个值而不给它一个全局名称(相反,块构建一个局部值并返回它);我们可以处理函数(通过构建一个将每个函数与其名称关联起来的表)等。Lua 为您提供能力;您构建机制。
版权所有 © 2003–2004 Roberto Ierusalimschy。保留所有权利。 |