我正在尝试了解#
操作员的规则。
考虑以下示例:
> t1 = table.pack(nil, 1, nil, 2)
> #t1
4
> for k, v in pairs(t1) do print(k, v) end
2 1
4 2
n 4
> t2 = table.pack(nil, 1, nil, 2, nil)
> #t2
2
> for k, v in pairs(t2) do print(k, v) end
2 1
4 2
n 5
> t3 = table.pack(nil, 1, nil, 2, nil, 3, nil)
> #t3
0
> for k, v in pairs(t3) do print(k, v) end
2 1
4 2
6 3
n 7
Run Code Online (Sandbox Code Playgroud)
我不能为此做头或尾。该n
字段的值始终与最初传递给的参数数量匹配table.pack
,但#
运算符返回的值无处不在,如以下摘要所示:
| n | # |
|---+---|
| 4 | 4 |
| 5 | 2 |
| 7 | 0 |
Run Code Online (Sandbox Code Playgroud)
规则是#
什么?换句话说,如果我看到来自
for k, v in pairs(sometable) do print(k, v) end
Run Code Online (Sandbox Code Playgroud)
...我该如何推导返回的值#sometable
?
(如果有关系,我正在使用lua5.3
。)
编辑: 我要补充的是,所有表t1
,t2
以及t3
在上面的例子中ipairs
回报什么。例如
> for i, v in ipairs(t0) do print(i, v) end
> -- no output
Run Code Online (Sandbox Code Playgroud)
nil
Lua中的Array和s是一个复杂的话题。
当您使用时table.pack
,它将计算参数数量并将表n
值设置为该值。如果您使用类似的表构造函数,则不是这种情况{1, nil, 3, nil}
。
该#
运营商,但是,做了略有不同。
从手册:
应用于表的长度运算符返回该表中的边框。表格中的边框是表格
t
中的任何自然索引,其中非nil值后跟一个nil值(当索引1为nil时为零)。
这就是说,对于桌子
t = {1, nil, 3, nil}
Run Code Online (Sandbox Code Playgroud)
它可能返回1
,因为t[1]
是1且t[2]
为nil,或者3
,因为t[3]
是3且t[4]
为nil。
该ipairs()
函数做的另一件事是:它实际上从1开始对索引进行计数,直到它在表中达到零为止,因此它将始终计数到表的第一个边界。
如果要让#
操作员返回n
表的值,请在Lua 5.2或更高版本中执行以下操作:
local t = {n=10}
setmetatable(t, {__len=function(self) return self.n end})
print(#t) -- Will print 10, even though t has 0 numeric indices
Run Code Online (Sandbox Code Playgroud)
但是请注意,这在基于Lua 5.1的LuaJIT中不起作用。
同样,您可以设置__ipairs
表的元方法,t
以便ipairs(t)
从计数到第一个nil元素1
,t.n
而不是第一个nil元素。
编辑:至于为什么ipairs
对您的示例不执行任何操作,这主要是由于我已经对ipairs进行了解释,但是由于表中的第一个键是nil
,因此立即假定它为空,因此不执行任何操作。
这并不是真正相关,因为您不应该依赖于此类特定于实现的行为,但是这是PUC Lua 5.3如何实现以下#
操作的操作符:
t = {1, nil, 3, nil}
Run Code Online (Sandbox Code Playgroud)
如您所见,Lua使用二进制搜索来找到边界,只有当您假设只有一个边界时才有意义。否则,它可能会随机跳过第一个,而只是通过向表中添加一个值而突然发现它。
还要记住,每次添加值时,表的数组部分不会增加。如果我没记错的话,它总是翻倍。因此,您可以有一个4元素表,添加一个元素,Lua会将数组大小增加到8。添加另外4个元素,它将增加到16,即使它仅包含9个元素。这是为了避免不必要的分配。