问题描述
我正在生成一个字符串,以表示表中编码的状态。通过更改某些表条目的值,状态将发生变化。我将永远不会(在调用下面的mkName()
之后)向表中添加密钥或从中删除键。
我希望字符串成为表中状态的一种“规范名称”,因此,如果我更改表中的值然后又将其改回,我希望该“名称”再次相同。当前,我直接在表上使用pairs()
来读取表中的所有值。该遍历顺序在值更改时是否稳定?
我的代码如下
local function mkName(t)
local name = ""
for k,v in pairs(t) do name = name .. k .. ":" .. v .. "," end
return name
end
local state = { a=1,b=2,c=3 }
local name1 = mkName(state)
state.b = 10
local name2 = mkName(state)
state.b = 2
local name3 = mkName(state)
-- Here I want name1 and name3 to be equal
print(name1,name2,name3,name1==name3)
这在我想要的意义上是有效且稳定的,但是next()
(由pairs()
使用)的官方文档说:
解决方法
我建议您不要依赖未承诺但可能会意外运行的内容,但要保证状态函数的遍历顺序稳定。可以这样完成:
-- Iterator to replace pairs():
local function ordered_pairs (t)
-- Get table keys:
local keys = {}
for key,_ in pairs (t) do
table.insert (keys,key)
end
-- Sort them:
table.sort (keys,function (a,b)
local type_a,type_b = type (a),type (b)
return type_a < type_b
or type_a == type_b and (type_a == 'number' or type_a == 'string') and a < b
or type_a == type_b and tostring (a) < tostring (b)
end)
-- Loop over the sorted keys:
local counter = 1
return function()
local key = keys [counter]
if key then
counter = counter + 1
return key,t [key]
end
end
end
-- Actually,it's a serialiser:
local function hash (t)
local serialised = {}
for key,value in ordered_pairs (t) do
table.insert (serialised,tostring (key) .. ':' .. tostring (value))
end
return table.concat (serialised,',')
end
-- Test:
local t = {a = 1,b = 2,c = 3}
print ('Stage 1 (b = 2):',hash (t))
t.b = 10
print ('Stage 2 (b = 10):',hash (t))
t.b = 2
print ('Stage 3 (b = 2):',hash (t))
首先对键进行排序(考虑所有可能的键类型,排序功能相当复杂)。然后按表的键顺序对其进行迭代。
如果需要,可以使用表的元表和pairs
用ordered_pairs
覆盖表的__pairs
。