在删除键时如何安全地迭代 lua 表

问题描述 投票:0回答:3

在我的主协程中,我根据用户操作从表中删除或添加条目。在后台,我想迭代表中的条目。如果我在一次迭代中错过了插入,我并不介意,只要我可以在下一次迭代之前捕获它。

使用

pairs
迭代它安全吗?或者我应该使用
next
来代替?

lua iteration volatile lua-table
3个回答
6
投票

您可以在遍历表时安全地删除条目,但无法创建新条目,即新键。不过,您可以修改现有条目的值。 (删除条目是该规则的特例。)


5
投票

你无法从这里到达那里。至少不是直接....

正如lhf所说,您可以在遍历表时修改或删除条目,但不能添加它们。结果......未定义。 (阅读:出于所有实际目的分支到超空间或同等空间。)

如果您坚持能够添加条目,则必须克隆表并使用一个副本进行迭代,另一个副本用于跟踪插入和删除。如果这本身不符合您的要求,您将不得不这样做:

  1. 创建一个空表用于添加表。
  2. 开始迭代主表。
  3. 找到要修改的条目后,就地修改它们。 (这是允许的。)
  4. 找到要删除的条目后,就地删除它们。 (这是允许的。)
  5. 当您找到要添加的条目时,将它们添加到另一个开始为空的表中。
  6. 完成迭代后,将添加表合并到主表中。
  7. 起泡沫。冲洗。重复。

您还可以采用其他类似的模式,但规则略有不同。例如,在步骤 5 和 6 之间,您可能希望在合并之前为添加的表条目插入对表遍历代码的递归调用,等等。您可能还必须跟踪主表和添加表中可能的删除如果这是可能的互动。


0
投票

现有的答案很好,但我想添加一个引用来源的答案。

next()
的文档警告:

在遍历表的过程中,不应该给表中不存在的字段赋值。不过,您可以修改现有字段。特别是,您可以将现有字段设置为 nil。

pairs()
的文档指向相同的警告(因为它在内部使用
next()
),因此在
pairs()
期间删除可以,但添加则不行。

旁注

ipairs()
没有指定任何限制! (它只是增加索引直到它达到零,所以插入可能会弄乱你的顺序,但行为是明确定义的。)

对于较旧的 lua: 在 5.3 上,文档使用了短语“next 的行为未定义”,这似乎更不祥。

© www.soinside.com 2019 - 2024. All rights reserved.