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

LeM*_*sel 18 lua

Lua有#运算符来计算用作数组的表的"长度".我检查了这个操作员,我感到很惊讶.

这是代码,我让它在Lua 5.2.3下运行:

t = {};
t[0] = 1;
t[1] = 2;
print(#t); -- 1 aha lua counts from one
t[2] = 3;
print(#t); -- 2 tree values, but only two are count
t[4] = 3;
print(#t); -- 4  but 3 is mssing?
t[400] = 400;
t[401] = 401;
print(#t); -- still 4, now I am confused?


t2 = {10, 20, nil, 40}
print(#t2); -- 4 but documentations says this is not a sequence?
Run Code Online (Sandbox Code Playgroud)

有人可以解释规则吗?

cub*_*l42 27

引用Lua 5.2参考手册:

表t的长度仅在表是序列时定义,即,对于某些整数n,其正数字键的集合等于{1..n}

#非序列上的运算符的结果是未定义的.但是当我们调用#非序列时,Lua的C实现会发生什么

背景:Lua中的表在内部分为数组部分和散列部分.这是一个优化.Lua试图避免经常分配内存,所以它预先分配下一个2的幂.这是另一个优化.

  1. 当数组部分中的最后一项是nil,结果#是通过bin搜索第一个零跟随键的数组部分找到的最短有效序列的长度.
  2. 当数组部分中的最后一项不是nilAND时,哈希部分为空,结果#是数组部分的物理长度.
  3. 当在阵列部分中的最后一项是不nil与散列部不是空的,结果#是通过binsearching散列部用于第一零-随后键(即这样的正整数中发现的最短有效序列的长度it[i] ~= nil并且t[i+1] == nil,假设数组部分充满了非nils(!).

这样的结果#几乎总是最短有效序列的(期望的)长度,除非在阵列部分表示非序列的最后一个元素是非零.然后,其结果是更大的比期望的.

这是为什么?这似乎是另一种优化(对于两个功率大小的阵列).#这些表的复杂性是O(1),而其他变体是O(log(n)).

  • 几年后,我编辑了这个答案,更深入地解释了 Lua 中表作为序列的含义。 (2认同)