我们知道在 Lua 中取 table
的长度,可以使用 #
。但是这里有个前提,就是 table
必须是一个序列。如果一个 table
有「空洞」,那么用 #
取到的结果将没有明确含义!!!
但是根据 Lua 官方文档的说法,这个行为是可以通过 __len
元方法来改变的:
A program can modify the behavior of the length operator for any value but strings through the __len metamethod
需要注意的是这个行为并不适用于 Lua 5.1,__len
对于 table
是从 5.2 以后才开始支持的。我们来验证下:
local t = {10, nil, 30, nil}
print(#t)
local mt = {
__len = function ()
return 4
end
}
setmetatable(t, mt)
print("==> ", getmetatable(t).__len())
print(#t)
-- Lua-5.1.4
-- output:
-- 1
-- ==> 4
-- 1
-- Lua-5.2.4
-- output:
-- 1
-- ==> 4
-- 4
也许有的同学还有疑问:那我们可不可以重载对于 string
的 #
运算?
local str = "test str"
local mt = getmetatable(str)
mt.__len = function ()
return 5
end
debug.setmetatable(str, mt)
print(#str)
-- output:
-- 8
答案显然是不可以的,Lua wiki 上也有标明:
All types except string now respect __len metamethod.
最后,Lua 的很多标准库均依赖 __len
的正确定义,如:table.insert
、table.remove
等等。如果需要重载 __len
时务必要格外小心,否则可能既没有获得什么好处,还会使 Lua 标准库无法正常工作。