改變物件的 metamethods

local Class = {}
Class.__meta = {__index=Class}
function Class.new() return setmetatable({}, Class.__meta)

假設我們想要使用 metatable 改變單個例項 object = Class.new() 的行為,

有一些錯誤需要避免:

setmetatable(object, {__call = table.concat}) -- WRONG

這將舊的 metatable 與新的 metatable 交換,從而打破了類的繼承

getmetatable(object).__call = table.concat -- WRONG AGAIN

請記住,表僅供參考; 實際上,物件的所有例項只有一個實際表,除非建構函式定義為 1 ,因此通過這樣做我們修改了類的所有例項的行為。

這樣做的一種正確方法:

不改變類:

setmetatable(
    object,
    setmetatable(
        {__call=table.concat},
        {__index=getmetatable(object)}
    )
)

這是如何運作的? - 我們在錯誤#1 中建立了一個新的 metatable,但是我們不是將它留空,而是為原始 metatable 建立一個軟拷貝。可以說新的 metatable 從原始的繼承,好像它本身就是一個類例項。我們現在可以覆蓋原始元表的值而無需修改它們。

改變類:

1 號(推薦):

local __instance_meta = {__index = Class.__meta}
-- metatable for the metatable
-- As you can see, lua can get very meta very fast
function Class.new()
    return setmetatable({}, setmetatable({}, __instance_meta))
end

2(少推薦):見 1

1 function Class.new() return setmetatable({}, {__index=Class}) end