元表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