在Lua中,我们可以通过table+function来模拟实现类。
而要模拟出类,元表(metatable)和__index元方法是必不可少的。
为一个表设置元表的方法:
table = {}
metatable = {}
setmetatable(table, metatable)
或者
table = setmetatable({},{})
下面看一个简单的例子:
local t = { k1 = "aaa"}local mt = { k2 = "bbb", __index = { k3 = "ccc" }}setmetatable(t, mt)print("k1:", t.k1, "k2:", t.k2, "k3:", t.k3)
输出:
k1: aaa k2: nil k3: ccc
从例子可以看出,查找表元素时会从表的元表的__index键中查找。
查找一个表元素的规则如下:
1.在表中查找,如果找到,返回该元素;如果找不到,继续2
2.判断该表是否有元表,如果没有,返回nil;如果有,继续3
3.判断元表中是否有__index方法,
如果__index方法为nil,返回nil;
如果__index方法是一个表,则重复 1,2,3;
如果__index方法是一个函数,则返回该函数的返回值。
除了有__index元方法外,还有__newindex,__add,__sub等很多原方法,可查看Lua文档
在了解了元表和元方法后,我们就可以模拟类的实现了。
local A = { a1 = "this is a1", a2 = 100}function A.new() local o = {} setmetatable(o, A) A.__index = A return oendfunction A:Print() print("This is A:Print ")endlocal a = A.new()a:Print()
输出结果:
This is A:Print
以上就是一个类的简单实现方式,当然,我们也可以把它的实现封装到一个function中,这样会更方便我们类的创建和使用。
下面是cocos2d引擎中,lua类的实现,以供参考:
View Codelocal setmetatableindex_setmetatableindex_ = function(t, index) if type(t) == "userdata" then local peer = tolua.getpeer(t) if not peer then peer = {} tolua.setpeer(t, peer) end setmetatableindex_(peer, index) else local mt = getmetatable(t) if not mt then mt = {} end if not mt.__index then mt.__index = index setmetatable(t, mt) elseif mt.__index ~= index then setmetatableindex_(mt, index) end endendsetmetatableindex = setmetatableindex_function class(classname, ...) local cls = {__cname = classname} local supers = {...} for _, super in ipairs(supers) do local superType = type(super) assert(superType == "nil" or superType == "table" or superType == "function", string.format("class() - create class \"%s\" with invalid super class type \"%s\"", classname, superType)) if superType == "function" then assert(cls.__create == nil, string.format("class() - create class \"%s\" with more than one creating function", classname)); -- if super is function, set it to __create cls.__create = super elseif superType == "table" then if super[".isclass"] then -- super is native class assert(cls.__create == nil, string.format("class() - create class \"%s\" with more than one creating function or native class", classname)); cls.__create = function() return super:create() end else -- super is pure lua class cls.__supers = cls.__supers or {} cls.__supers[#cls.__supers + 1] = super if not cls.super then -- set first super pure lua class as class.super cls.super = super end end else error(string.format("class() - create class \"%s\" with invalid super type", classname), 0) end end cls.__index = cls if not cls.__supers or #cls.__supers == 1 then setmetatable(cls, {__index = cls.super}) else setmetatable(cls, {__index = function(_, key) local supers = cls.__supers for i = 1, #supers do local super = supers[i] if super[key] then return super[key] end end end}) end if not cls.ctor then -- add default constructor cls.ctor = function() end end cls.new = function(...) local instance if cls.__create then instance = cls.__create(...) else instance = {} end setmetatableindex(instance, cls) instance.class = cls instance:ctor(...) return instance end cls.create = function(_, ...) return cls.new(...) end return clsend