Lua 表格大小

lua-users home
wiki


[!] 版本说明: 本文描述的问题已得到解决。从 5.0 版本开始,n 值不再用于表格列表组件的大小计算。

问题

表格包含成员 "n" 作为表格插入的优化。例如,从手册中:-

getn (table)
返回表格作为列表时的大小。如果表格具有数值型的 n 字段,则此值即为表格的大小。否则,大小为表格中具有非空值的最大的数值索引。此函数可以在 Lua 中定义
function getn (t)
  if type(t.n) == "number" then return t.n end
  local max = 0
  for i, _ in t do
    if type(i) == "number" and i>max then max=i end
  end
  return max
end

由于表格的双重性质,即它们可以同时是列表和字典,"n" 可能会与表格中的用户数据冲突。以下部分列出了解决此问题的几种方法。请随时在解决方案旁边发表评论或提出您自己的解决方案。请留下您的姓名或首字母,以便统计 "投票"。

这可以更好地定义。n 字段不是 "表格大小",也不用于 "表格插入"。(当然,Lua API 函数名称和文档混淆了这个问题。)表格是 Lua 中的纯数据类型,而列表则不是。在表格数据类型之上实现列表有几种方法。由于列表是一种重要的数据类型,即使在 VM 本身中也需要(用于可变参数),标准库提供了一种实现,包括使用 n 字段表示列表大小以及用于确定任意表格的 "列表组件" 的算法(这就是 getn 在没有 n 字段时所做的)。

替代解决方案

这不是问题,保留它。

您的编程风格可能不需要在同一个表格中混合列表和字典,因此这可能不是问题。

所以,基本上你不想破坏向后兼容性,你发现因为表的大小被命名为“n”,任何冲突的 bug 都很容易找到,而且你也不介意你的表大小始终被称为“n”。为什么不消除这个问题,正如你所说,“迟早会咬你”,而且你可以灵活地命名?我不记得看到过任何使用 n 设置表大小的代码(所以没有向后兼容问题?)。--NDT

我认为这总结了它 :-)。如果我使用一个表作为向量,我不会把它用作字典,尽管我可能会在里面放我自己的键。在这种情况下,我只是不使用键 n 或任何数字键。这与将键存储在任何以表实现的对象中没有什么不同;你必须避免使用对象的定义键,这些键应该是有文档记录的。碰巧的是,我确实有使用 n 设置表大小的代码——除非你已经看过所有 Lua 代码,否则我认为你不能轻率地声称没有向后兼容问题。无论如何,我认为使用 vec.n 而不是 getn(vec) 来检索表大小是很常见的,因为如果你能确保键存在(甚至 vec.n or getn(vec)),这会快得多。-- RiciLake

“希望有文档记录” :-) 正是这种混乱可以避免。表是多用途的,可以作为列表或字典使用,这意味着不应该应用这种类型的限制。我个人宁愿忍受修复可能被此破坏的代码。我认为 Lua 作为一种语言还处于起步阶段,它的根源在于方便的嵌入和配置。它仍然需要解决一些小问题,比如这个,才能被认为是一种严肃的脚本语言。我不确定成为“Python 杀手”是否是它的设计目标,但我相信作者热衷于看到语言及其用户群的发展。随着 Lua 的改进,这种情况将继续发生。:-) --NDT

公平地说,还有其他几个地方,其中一个是 call。但是,编写替换函数肯定很容易,而且没有人强迫你使用 tinsert 和 tremove -- RiciLake

它应该被重命名

“n”变量应该重命名为不太可能冲突的名称,例如“__n__”。

setn()

setn() 将是一个更好的解决方案,可以补充 getn()

len[t]

        settagmethod(tag({}), "index",
              function(v, k) if k == "n" then return len[v] end end)

所以,我愿意改变我的投票 --RiciLake

这也与 getnsetn 兼容;如果您想要这样做,只需包含

        function getn(v) return len[v] end
        function setn(v, n) len[v] = n end

请添加任何其他解决方案...

实现一个不可覆盖的 getnEx() 函数

function getn (t)
  if type(t.n) == "number" then return t.n end
  return getnEx(t) -- internal function
end
如果 getn() 函数导致问题,人们可以忽略它,直接使用 getnEx() 函数,该函数不需要变通方法。getnEx() 本质上等同于
function getnEx (t)
  local max = 0
  for i, _ in t do
    if type(i) == "number" and i>max then max=i end
  end
  return max
end

--Paul Hsieh

投票结果

请更新下面的列表。如果您希望匿名投票,只需在下面添加投票(但听到您的意见会很好 :-)。


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2019 年 3 月 8 日下午 10:27 GMT (差异)