改變物件的 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