元表html
Lua中每一個值均可具備元表。 元表是普通的table,定義了原始值在某些特定操做下的行爲。你可經過在值的原表中設置特定的字段來改變做用於該值的操做的某些行爲特徵。例如,當數字值做爲加法的操做數時,Lua檢查其元表中的"__add"字段是否有個函數。若是有,Lua調用它執行加法。函數
咱們稱元表中的鍵爲事件(event),稱值爲元方法(metamethod)。前述例子中的事件是"add",元方法是執行加法的函數。lua
不能從Lua中改變其餘類型的元表(除了使用調試庫);必須使用C API才能作到。表和完整的用戶數據具備獨立的元表(儘管多個表和用戶數據可共享元表);每種其餘類型的全部值共享一個元表。因此,全部數字共享一個元表,字符串也是,等等。調試
一個 metatable 能夠控制一個對象作數學運算操做、比較操做、鏈接操做、取長度操做、取下標操做時的行爲, metatable 中還能夠定義一個函數,讓 userdata 做垃圾收集時調用它。 對於這些操做,Lua 都將其關聯上一個被稱做事件的指定健。 當 Lua 須要對一個值發起這些操做中的一個時, 它會去檢查值中 metatable 中是否有對應事件。 若是有的話,鍵名對應的值(元方法)將控制 Lua 怎樣作這個操做code
每種操做都有元表(xx的元表__xx):sub,mul,div,mod,pow,unm,concat,len,eq,lt,le,index,newindex,callorm
其中,__index是取下標操做用於訪問 table[key], __newindex是賦值給指定下標 table[key] = value, __call是當Lua調用一個值時調用htm
設置和查詢元表值,setmetatable(只能用於table)和getmetatable(用於任何對象)對象
下面例子爲一個table設置加操做繼承
重載操做符事件
local mt = {} function mt.__add(a, b) return 'table + ' .. b end local t = {} setmetatable(t, mt) print(t + 1) -- table + 1
使用metatable能夠模擬出面向對象
local Bird = {} function Bird:new() local b = {isDead = false} setmetatable(b, self) self.__index = self return b end function Bird:fly() print("fly ~~~") end local bird1 = Bird:new() print(bird1:fly()) -- fly ~~~ print(bird1.isDead) -- false
這裏利用index元表,當咱們訪問一個表中的元素不存在時,則會觸發去尋找__index元方法。因此就能夠模擬出類的封裝。
Cocos2d-x-lua裏有更完善的類和繼承的class模擬
table經過對newindex元表的值處理,能夠保護table不被修改
例如cocos2d-x裏有個這樣屏蔽全局變量的函數:
function cc.disable_global() setmetatable(__g, { __newindex = function(_, name, value) error(string.format("USE \" cc.exports.%s = value \" INSTEAD OF SET GLOBAL VARIABLE", name), 0) end }) end
rawget 和 rawset 這兩個函數,能夠避免Lua使用 __index 和 __newindex。通常用在index,newindex元表中以免死循環。
local Bird = {} function Bird:new() local b = {isDead = false} setmetatable(b, self) self.__index = function(t, key)return 1000 end return b end w = Bird:new() print(w["haha"]) -- 1000 print(rawget(w, w["haha"])) -- nil w["haha"] = 10 print(w["haha"]) -- 10 print(rawget(w, w["haha"])) -- nil rawset(w, w["haha"], 1) print(w["haha"]) -- 10 print(rawget(w, w["haha"])) -- 1