Lua:大小写不敏感引用table键及递归设置元表

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章