如果只修改字段值,那么`next()`是否有稳定的顺序?

我正在生成一个字符串来表示编码在表格中的状态。该状态将通过更改某些表项的值来改变。我从不会在下面调用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)
-- 在这里,我希望name1和name3相等
print(name1, name2, name3, name1==name3)

这个方法可行且稳定,但是next()官方文档(由pairs()使用)说:

枚举索引的顺序没有指定,即使对于数值索引也是如此。(要按数字顺序遍历表,请使用数值for循环或ipairs函数。)

难道在后续调用pairs()时迭代顺序可能会改变吗?

点赞
用户6632736
用户6632736

我建议您不要依赖于没有承诺但可能意外起作用的内容,而是保证您的状态函数具有稳定的遍历顺序。可以像这样完成:

- 用于替换 pairs() 的迭代器:
local function ordered_pairs (t)
    - 获取表键:
    local keys = {}
    for key, _ in pairs (t) do
        table.insert (keys, key)
    end
    - 对它们进行排序:
    table.sort (keys, function (a, b)
        本地 type_a,type_b = type (a),type (b)
        返回 type_a <type_b
            或type_a == type_b且(type_a =='number'或type_a =='string')且a <b
            或type_a == type_b且tostring(a)<tostring(b)
    end)
    - 循环遍历排序的键:
    本地计数器= 1
    返回function()
        本地键=键 [counter]
        如果钥匙呢
            计数器=计数器+ 1
            返回键,t [key]
        结束
    end
end

- 实际上,它是一个串行化器:
local function hash (t)
    本地串行= {}
    for key,value在ordered_pairs(t)中进行处理
        table.insert (serialised,tostring(key)..':'.. tostring(value))
    end
    返回table.concat(serialised,','end

- 测试:
本地t = {a = 1,b = 2,c = 3}
print'阶段1(b = 2):',hash(t))
t.b = 10
print'阶段2(b = 10):',hash(t))
t.b = 2
print'阶段3(b = 2):',hash(t))

首先按顺序排列键(排序函数相当复杂,以考虑所有可能的键类型)。然后按其键的顺序遍历表格。

如果您希望,您可以使用其metatable和__pairs,用ordered_pairs覆盖表格的pairs。

2020-10-19 08:52:56