为什么在Lua中,使用null索引的`table.remove`仍然有效

huangapple go评论58阅读模式
英文:

Why lua table.remove with null index still works

问题

我注意到在使用 table.remove() 的 Lua 代码中,当我在索引位置传递 nil 时,它会删除最后一个元素。这对我来说有点反直觉。

> local tbl = {"this","is","a","list"}
  table.remove(tbl,nil)

将导致列表中的最后一个元素被删除。

> for k,v in ipairs(tbl) do 
     print(k,v)
  end
1       this
2       is
3       a

这个行为有具体的原因吗?

英文:

I am seeing the behavior in Lua code that uses table.remove() which removes the last element when I am passing nil in place of the index . It was counter-intuitive to me.

> local tbl = {"this","is","a","list"}
  table.remove(tbl,nil)

will result in the last element deleted from list

> for k,v in ipairs(tbl) do 
     print(k,v)
  end
1       this
2       is
3       a

is there a specific reason for this behavior ?

答案1

得分: 4

>这个行为有特定的原因吗?

是的。table.removetable.insert 最常用作 Lua 表的“push”和“pop”等效操作,用于在表的末尾添加或移除元素,将其视为“堆栈”。明确提供索引实际上是“较少见”的情况(而且应该是这样,因为它在最坏情况下需要线性时间,因为需要移动项,而仅在末尾进行推送/弹出是平摊的常数时间)。

基本上,您可以将这看作是一个合理处理的特例,事实上它是常见情况。传递 nil 或“none” 使 Lua 获取 #tbl 的“默认值”作为索引。

table.remove(tbl)table.remove(tbl, nil) 不同;一个将“none”(超出堆栈范围)作为 index,另一个传递显式的 nil。Lua 可以区分这些情况(某些库函数也是如此),但如果它这样做会对程序员造成困扰——他们通常期望 nil 和“none”被视为相同的——那就会令人困惑。

如果您不喜欢使用语句 table.remove(tbl) 来移除最后一个元素,您可以将其设置为 nil,这是等效的:tbl[#tbl] = nil(除了 table.remove 将返回已移除的元素以方便使用,但这只在表达式中有意义)。

类似地,语句 table.insert(tbl, x) 等效于 tbl[#tbl + 1] = x。特别注意,对于 x = niltable.insert 是一个无操作(这通常被认为是一个隐患)。

英文:

> is there a specific reason for this behavior ?

Yes. table.remove and table.insert are most often used as "push" and "pop" equivalents to remove or add elements at the end of a Lua table, treating it as a "stack". Explicitly providing an index is in fact the "rarer" case (and should be, since it has worst-case linear time due to needing to shift items, whereas just pushing/popping at the end is amortized constant time).

Essentially, you can view this as a sanely handled edge case, which turns out to be the common case. Passing nil or "none" makes Lua take the "default value" of #tbl as index.

table.remove(tbl) and table.remove(tbl, nil) are not the same; one passes "none" (out of stack bounds) as index, the other passes an explicit nil. Lua can distinguish these (and some library functions do), but it would be confusing to programmers - who usually expect nil and "none" to be treated the same - if it did.

If you're not comfortable with using the statement table.remove(tbl) to remove the last element, you might as well set it to nil, which is equivalent: tbl[#tbl] = nil (except table.remove will return the removed element for convenience, but this only matters in expressions).

Similarly, the statement table.insert(tbl, x) is equivalent to tbl[#tbl + 1] = x. Note in particular that for x = nil, table.insert is a no-op (this is often considered a footgun).

huangapple
  • 本文由 发表于 2023年2月27日 17:27:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/75578694.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定