【发布时间】:2011-11-13 15:07:41
【问题描述】:
我遇到两个库 L、M 正在尝试为 _G 设置元表(分别命名为 mL、mM)的情况。元表中唯一的东西是 __index。
如何链接这两个元表,以便如果一个中的 __index 失败,它会调用另一个中的索引?
【问题讨论】:
标签: lua
我遇到两个库 L、M 正在尝试为 _G 设置元表(分别命名为 mL、mM)的情况。元表中唯一的东西是 __index。
如何链接这两个元表,以便如果一个中的 __index 失败,它会调用另一个中的索引?
【问题讨论】:
标签: lua
有一个存储mL 和mM 的元表,如果一个返回nil,检查另一个:
local metatbl = {}
metatbl.tbls = {mL, mM};
function metatbl.__index(intbl, key)
for i, mtbl in ipairs(metatbl.tbls) do
local mmethod = mtbl.__index
if(type(mmethod) == "function") then
local ret = mmethod(table, key)
if ret then return ret end
else
if mmethod[key] then return mmethod[key] end
end
return nil
end
end
setmetatable(_G,metatbl)
【讨论】:
假设您的代码在某个时刻可以摆弄_G 的元表本身,在库搞砸之后,要修复 L 和 M 所做的事情,您可以坚持使用自己的元表来进行组合搜索,例如:
combined_metatable = {
__index = function (t, k)
return mL.__index (t, k) or mM.__index (t, k)
end
}
setmetatable (_G, combined_metatable)
这样做的好处是不用摆弄mL 或mM 自己。
如果您没有事后有机会更正事情,您可以修改库元表的 __index 条目来进行组合搜索:
local original_mM_index = mM.__index
local original_mL_index = mL.__index
local function L_then_M_index (t, k)
return original_mL_index (t, k) or original_mM_index (t, k)
end
mL.__index = L_then_M_index
mM.__index = L_then_M_index
[请注意,由于两个库元表都已修改,因此无论最后安装哪个都有效(“赢得”比赛)。]
【讨论】:
使用 __metatable 给他们一个实际上不是元表的表,或者给库一个不同的 setmetatable:这样他们就不能改变你的 _G 元表。
getmetatable(getfenv()).__metatable = function ( o ) return { } end
或
local orig_setmetatable = setmetatable
function setmetatable ( ob , mt )
if ob == getfenv() or ob == _G then
return ob
else
return orig_setmetatable(ob,mt)
end
end
(取决于图书馆如何做事)
如果您仍然想跟踪它对元表所做的事情;在返回 ob 之前查看 mt (如果你真的想链接 __index 查找;添加到表中):
local env_indexes = {}
setmetatable(_G,{__index=function(t,k) for i,m in ipairs(env_indexes) do local v=m[k]; if v then return v end end return nil end } )
local orig_setmetatable = setmetatable
function setmetatable ( ob , mt )
if ob == _G then
table.insert ( env_indexes , mt.__index )
return ob
else
return orig_setmetatable(ob,mt)
end
end
否则这对图书馆来说是非常糟糕的做法;告诉作者不要!
【讨论】: