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