Lua:大小写不敏感引用table键及递归设置元表
Lua中table的键是区分大小写的,即:
local t = {}
t.a = "a"
print(t.A) -- nil
有时候希望可以大小写不敏感地访问、引用table的键,可以通过设置元表实现:
local t = {}
t.a = "a"
t.B = "B"
t.c = "c"
local mt = {}
mt.__index = function(t, k)
local v
-- t中含大量键时开销极大
for tk, tv in pairs(t) do
-- 大小写不敏感比较键
if string.lower(tk) == string.lower(k) then
v = tv
break
end
end
return v
end
setmetatable(t, mt)
-- 正常调用
print(t.a) -- a
-- 小写转大写调用
print(t.b) -- B
-- 大写转小写调用
print(t.C) -- c
有两个问题:
1.这样的代码仅适用于功能,不适用于性能。
当t中包含的键非常多时,而我们恰好触发原方法__index,就导致一次遍历。
这样做开销极大,在上量跑压力时有很大的问题。(耗费大量CPU做遍历)
2.只针对t有效,t的子孙table,没有设置元表,仍然大小写敏感。
于是我们需要“递归设置元表”。
我这里指的是,将一个元表设置到某个table,以及table中所有的子孙table。
local mt = {}
mt.__index = function(t, k)
local v
-- t中含大量键时开销极大
for tk, tv in pairs(t) do
-- 大小写不敏感比较键
if string.lower(tk) == string.lower(k) then
v = tv
break
end
end
return v
end
-- 递归设置元表
function recurrence_setmetatable(t, mt)
if type(t) ~= "table" then
return
end
-- 设置table元表
setmetatable(t, mt)
-- 递归table设置子元表
for _, tv in pairs(t) do
if type(tv) == "table" then
recurrence_setmetatable(tv, mt)
end
end
end
local t = {}
t.test1024 = {}
t.test1024.test1280 = {}
t.test1024.test1280.key = "value"
t.a = "a"
recurrence_setmetatable(t, mt)
print(t.TEST1024.TEST1280.KEY) -- value
print(t.a) -- a