如何在Lua表中安全地迭代,同时删除键?

10
在我的主协程中,我根据用户操作从表中删除或添加条目。在后台,我希望迭代表中的条目。如果我在一次迭代中错过了插入,但能在下一次迭代之前捕获它,那对我来说没什么关系。
使用pairs函数迭代表是否安全?还是应该使用next函数?
3个回答

6

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


5
你从这里无法直接到达目的地...如lhf所说,在遍历表时可以修改或删除条目,但不能添加条目。结果是未定义的。(意思是:实际上相当于进入超空间或等效处理)。
如果你坚持要能够添加条目,则必须克隆你的表并使用一个副本进行迭代,另一个副本用于跟踪插入和删除。如果这本身不符合你的要求,则必须采取以下措施:
  1. 创建一个空表以用于添加表项。
  2. 开始遍历主表。
  3. 在找到要修改的条目时,请直接进行修改。(这是允许的)
  4. 在找到要删除的条目时,请直接进行删除。(这是允许的)
  5. 在找到要添加的条目时,请将它们添加到最初为空的另一个表中。
  6. 完成迭代后,将添加表合并到主表中。
  7. 重复以上步骤。
还有其他类似规则略有不同的模式可供使用。例如,在第5和第6步之间,您可能需要插入递归调用以遍历添加的表项,等等。如果可能出现交互,则还必须跟踪主表和添加表中的可能删除。

2
现有的答案都很好,但我想补充一个引用来源的答案。关于next()的文档警告说:

在遍历表时,不应为不存在的字段赋值。但可以修改已存在的字段。特别是可以将已存在的字段设置为nil。

关于pairs()的文档也指出了同样的注意事项(因为它在内部使用了next()),所以在pairs()中删除是可以的,但添加则不行。 顺便提一下ipairs()没有指定任何限制!(它只是递增索引直到达到nil,所以插入可能会破坏顺序,但行为是明确定义的。)
对于旧版本的lua:在5.3版本中,文档使用了“next的行为是未定义的”这个短语,听起来更加不祥。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接