英文:
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.remove
和 table.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 = nil
,table.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).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论