第一版针对 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。保留所有权利。 | ![]() |