第一版针对 Lua 5.0 编写。虽然在很大程度上仍然适用于后续版本,但存在一些差异。
第四版针对 Lua 5.3,可在 亚马逊 和其他书店购买。
购买本书,您还可以帮助支持 Lua 项目


12.1.2 – 保存带有循环的表

要处理具有通用拓扑结构(即,带有循环和共享子表的)的表,我们需要采用不同的方法。构造函数无法表示此类表,因此我们不会使用它们。要表示循环,我们需要名称,因此我们的下一个函数将获取要保存的值及其名称作为参数。此外,我们必须跟踪已保存表的名称,以便在检测到循环时重用它们。我们将使用一个额外的表进行此跟踪。此表将把表作为索引,并将它们的名称作为关联值。

我们将保留一个限制,即我们想要保存的表仅具有字符串或数字作为键。以下函数序列化这些基本类型,返回结果

    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 为您提供能力;您构建机制。