【元表】
元表中的键为事件(event),称值为元方法(Metamethod)。
通过函数getMetatable查询任何值的元表,通过函数setMetatable替换表的元表。
setMetatable(只能用于table)和getMetatable(用于任何对象)
语法:setMetatable (table,Metatable),对指定table设置Metatable 【如果元表(Metatable)中存在__Metatable键值,setMetatable会失败】
语法:tMeta = getMetatable (tab),返回对象的元表(Metatable) 【如果元表(Metatable)中存在__Metatable键值,当返回__Metatable的值】
【元方法】
元表可以控制对象的数学运算、顺序比较、连接、取长、和索引 *** 作的行为。
当Lua对某值执行其中一个 *** 作时,检查该值是否含有元表以及相应的事件。如果有,与该键关联的值(元方法)控制Lua如何完成 *** 作。
每个 *** 作的键是由其名字前缀两个下划线“__”的字符串;例如, *** 作“加(add)”的键是字符串"__add"。
特别一提,要获取给定对象的元方法,我们使用表达式
Metatable(obj)[event]
它应被解读为
rawget(getMetatable(obj) or {},event)
就是说,访问一个元方法不会调用其他元方法,而且访问没有元表的对象不会失败(只是结果为nil)。
"add": + *** 作。
下面的getbinhandler函数定义Lua如何选择二元 *** 作的处理程序。首先尝试第一 *** 作数,如果它的类型没有定义该 *** 作的处理程序,则尝试第二 *** 作数。
function getbinhandler (op1,op2,event)
return Metatable(op1)[event] or Metatable(op2)[event]
end
事件:
add
sub
mul
div
mod
pow
unm 一元 *** 作-
concat 连接 *** 作..
len 取长 *** 作#
eq 相同 *** 作==
lt 小于 *** 作<
le
index 索引访问table[key],参数table,key
newindex 索引赋值table[key] = value,参数table,key,value
call lua调用
__index元方法:
按照之前的说法,如果A的元表是B,那么如果访问了一个A中不存在的成员,就会访问查找B中有没有这个成员。这个过程大体是这样,但却不完全是这样,实际上,即使将A的元表设置为B,而且B中也确实有这个成员,返回结果仍然会是nil,原因就是B的__index元方法没有赋值。按照我的理解,__index方法是用来确定一个表在被作为元表时的查找方法。
【用户数据和元方法】
Userdata:
A userdata offers a row memory area,with no predefined operations in Lua,which we can use to store anything (分配指定数量的内存在栈上,把数据已用户自定义的数据结构存放进去)
lua_newuserdata() -- allocates a block of memory with the given size,pushes the corresponding userdatum on the stack,and returns the block address
Metatable:
The usual method to distinguish one type of userdata from other userdata is to create a unique Metatable for that type.
Lua code cannot change the Metatable of a userdatum,it cannot fake our code (Lua 不能改变userdata里面的Metatable,所以userdata的Metatable可以用作唯一标示符来识别userdata,这里Metatable拿来判断是否传入了正确的userdata参数)
【继承】
cocos2dx里的继承:
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原理就不细说了,修改__index,使得在访问其成员的时候能遍历所有的supers父类去查找该成员(类似Js里的原型链,但那是一条链,这里lua可自由发挥)。
他的第一个参数是类名,后面的参数可以是父表或者函数,函数的话只能有一个,是用来作为创建函数的__create,会在.new的时候被调用。
使用方法:
local UIScene = class("UIScene")UIScene.__index = UIScenefunction UIScene.extend(target) local t = tolua.getpeer(target) if not t then t = {} tolua.setpeer(target,t) end setMetatable(t,UIScene) return targetendfunction UIScene.create() local scene = cc.Scene:create() local layer = UIScene.extend(cc.Layer:create()) layer:init() scene:addChild(layer) return scene endgetpeer/setpeer我还不是很理解,从网上找到说明留着消化:
Those are tolua functions. The tolua manual (for example here) has explanations for them.tolua.setpeer (object,peer_table) (lua 5.1 only)Sets the table as the object's peer table (can be nil). The peer table is where all the custom lua fIElds for the object are stored. When compiled with lua 5.1,tolua++ stores the peer as the object's environment table,and uses uses lua_gettable/settable (instead of lua_rawget/set for lua 5.0) to retrIEve and store fIElds on it. This allows us to implement our own object system on our table (using Metatables),and use it as a way to inherit from the userdata object. ConsIDer an alternative to the prevIoUs example:-- a 'LuaWidget' classLuaWidget = {}LuaWidget.__index = LuaWidgetfunction LuaWidget:add_button(caption) -- add a button to our Widget here. 'self' will be the userdata Widgetendlocal w = Widget()local t = {}setMetatable(t,LuaWidget) -- make 't' an instance of LuaWidgettolua.setpeer(w,t) -- make 't' the peer table of 'w'set_parent(w) -- we use 'w' as the object Noww:show() -- a method from 'Widget'w:add_button("Quit") -- a method from LuaWidget (but we still use 'w' to call it)When indexing our object,the peer table (if present) will be consulted first,so we don't need to implement our own __index Metamethod to call the C++ functions.tolua.getpeer (object) (lua 5.1 only)RetrIEves the peer table from the object (can be nil).总结
以上是内存溢出为你收集整理的lua——元表、元方法、继承全部内容,希望文章能够帮你解决lua——元表、元方法、继承所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)