为什么Lua的长度(#)运算符返回意外的值?

Lua 中有 # 运算符用于计算作为数组使用的表的“长度”。 我检查了这个运算符,非常惊讶。

这是我让它在 Lua 5.2.3 中运行的代码:

t = {};
t[0] = 1;
t[1] = 2;
print(#t); -- 1 哈,Lua 从 1 开始计数
t[2] = 3;
print(#t); -- 2 三个值,但只有两个被计数
t[4] = 3;
print(#t); -- 4 但是 3 去哪里了?
t[400] = 400;
t[401] = 401;
print(#t); -- 仍然是 4,现在我困惑了?

t2 = {10, 20, nil, 40}
print(#t2); -- 4 但是文档说这不是一个序列?

谁能解释一下规则?

点赞
用户5386097
用户5386097

在 Lua 中,只有符合特定格式的表格被认为是数组。它们并不像 C 语言中的数组那样是真正的数组。表格仍然是哈希表。但是,表格的键是从 1 到 N 连续的数字。Lua 数组是单位偏移的,而不是零偏移的。

最终的结论是,如果你不知道你所建立的表格是否符合 Lua 数组的标准,那么你必须遍历表格中的项来确定表格的长度。这是唯一的方法。以下是实现此功能的函数:

function table_count(T)
  local count = 0
  for _ in pairs(T) do count = count + 1 end
  return count
end

如果你使用以下方式的 "insert" 函数填充表格,则可以确保生成一个 "数组" 表格。

s={}
table.insert(s,[你想存储的任何内容])

table.insert 可以在循环中使用,也可以从代码的其他地方调用。关键在于,如果你以这种方式向表格中添加项,则它将成为一个数组表格,你可以使用 # 操作符来确定表格中有多少项,否则你必须遍历表格中的项来计算数量。

2021-09-30 00:06:39
用户7787852
用户7787852

这个迭代器 应该 获取数组的所有值:

function npairs(t)
  local i = 0
  local n = #t
  return function()
    i = i + 1
    if i <= n then return i、t[i] end
  end
end

但正如顶部答案所说:

在那个时候调用 #t 的行为对于不是序列的表是未定义的。

结果在Lua的不同实现中也是不同的,例如,

给定:

local a = { 1nil2nil3nil4 }
for k、v in npairs(a)do
  print(k、v)
end

Lua 5.4.4 打印:

1   1
2   nil
3   2
4   nil
5   3
6   nil
7   4

而 LuaJIT 打印:

1   1

因此,我不信任这种情况下长度运算符。

这个迭代器似乎在 LuaJIT 中也可以工作,尽管速度肯定较慢:

function npairstlocal in = 0、0
  local indices = {}
  for k in pairstdo 
    if type(k) == "number" and k > n then 
      n = k 
    end
  end
  return function()
    i = i + 1
    if i <= n then return i、t[i] end
  end
end

测试:

local a = { 1nil2nil3nil4nilnil }
for k、v in npairs(a)do
  print(k、v)
end

输出:

1   1
2   nil
3   2
4   nil
5   3
6   nil
7   4

这个将跳过具有 nil 值的索引:

function npairstlocal in = 0、0
  local indices = {}
  for k in pairstdo 
    if type(k) == "number" and k > n then 
      n = k 
    end
  end
  return function()
    while i < n do
      i = i + 1
      if t[i] ~= nil then
        return i、t[i]
      end
    end
  end
end

测试:

local a = { 1nil2nil3nil4nilnil }
for k、v in npairs(a)do
  print(k、v)
end

输出:

1   1
3   2
5   3
7   4
2023-02-26 20:59:56