2011-11-13 13 views
4

我有一個情況,其中兩個庫L,M正試圖爲_G設置一個metatable(分別命名爲mL,mM)。在metatables中唯一的東西是__index。鏈Lua metatables

如何鏈接這兩個metatables,以便在__index中一個失敗時調用另一箇中的索引?

回答

2

有一個元表存儲都mLmM,如果一個返回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) 
+0

-1的任何原因? –

1

假設有一個點,你的代碼可以與_G的元表本身不甘示弱,庫後已經打亂有關,要解決什麼L和M沒有,你可以貼在自己的元表,做組合搜索,例如:

combined_metatable = { 
    __index = function (t, k) 
       return mL.__index (t, k) or mM.__index (t, k) 
      end 
} 

setmetatable (_G, combined_metatable) 

這已不是優勢擺弄mLmM自己。

如果沒有有機會改正的事情之後,其實你可以只修改庫元表的__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 

[注意既圖書館metatables被修改,這將工作取決於最後安裝(「贏得」競爭)。]

1

使用__metatable給他們一個實際上不是metatable的表或給圖書館一個不同的setmetatable:這樣他們不能改變你的_G metatable。

getmetatable(getfenv()).__metatable = function (o) return { } end 

OR

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(如果你確實想鏈__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 

否則,這是非常不好的做法爲圖書館做;告訴作者不要!