LUA教程保存带循环的table-50

针对普通拓扑概念上的带有循环表和共享子表的table,我们需要另外一种不同的方法来处理。构造器不能很好地解决这种情况,我们不使用。为了表示循环我们需要将表名记录下来,下面我们的函数有两个参数:table和对应的名字。另外,我们还必须记录已经保存过的table以防止由于循环而被重复保存。我们使用一个额外的table来记录保存过的表的轨迹,这个表的下表索引为table,而值为对应的表名。

我们做一个限制:要保存的table只有一个字符串或者数字关键字。下面的这个函数序列化基本类型并返回结果。

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这个参数是上面提到的记录已经保存的表的踪迹的table。

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?
           -- use its previous name
           io.write(saved[value], "\n")
       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

保存的table为:

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]

(实际的顺序可能有所变化,它依赖于table遍历的顺序,不过,这个算法保证了一个新的定义中需要的前面的节点都已经被定义过)
如果我们想保存带有共享部分的表,我们可以使用同样table的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"

然而如果我们使用同一个saved表来调用save函数:

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中常用的方法,当然也有其他一些方法可以解决问题。比如,我们可以不使用全局变量名来保存,即使用封包,用chunk构造一个local值然后返回之;通过构造一张表,每张表名与其对应的函数对应起来等。Lua给予你权力,由你决定如何实现。


发布日期:

所属分类: 易语言 标签: