zoukankan      html  css  js  c++  java
  • lua——元表、元方法、继承

    【元表】

    元表中的键为事件(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 cls
    end
      原理就不细说了。改动__index。使得在訪问其成员的时候能遍历全部的supers父类去查找该成员(类似js里的原型链,但那是一条链,这里lua可自由发挥)。

      他的第一个參数是类名,后面的參数能够是父表或者函数,函数的话仅仅能有一个,是用来作为创建函数的__create,会在.new的时候被调用。

      用法:

    local UIScene = class("UIScene")
    UIScene.__index = UIScene
    
    function UIScene.extend(target)
        local t = tolua.getpeer(target)
        if not t then
            t = {}
            tolua.setpeer(target, t)
        end
        setmetatable(t, UIScene)
        return target
    end
    
    function UIScene.create()
        local scene = cc.Scene:create()
        local layer = UIScene.extend(cc.Layer:create())
        layer:init()
        scene:addChild(layer)
        return scene   
    end
      getpeer/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' class
    LuaWidget = {}
    LuaWidget.__index = LuaWidget
    
    function LuaWidget:add_button(caption)
        -- add a button to our widget here. 'self' will be the userdata Widget
    end
    
    local w = Widget()
    local t = {}
    setmetatable(t, LuaWidget) -- make 't' an instance of LuaWidget
    
    tolua.setpeer(w, t) -- make 't' the peer table of 'w'
    
    set_parent(w) -- we use 'w' as the object now
    
    w: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).



  • 相关阅读:
    连续3年!SpreadJS 纯前端表格控件荣获“中国优秀软件产品”
    终于有一款组件可以全面超越Apache POI
    List<Object> 多条件去重
    xml文档的解析并通过工具类实现java实体类的映射:XML工具-XmlUtil
    soap get/post请求
    map转java对象
    springboot postman 对象里传时间格式问题
    spring boot的多环境部署
    Hibernate 之 @Query查询
    利用maven命令将外部jar包导进maven仓库
  • 原文地址:https://www.cnblogs.com/claireyuancy/p/7353196.html
Copyright © 2011-2022 走看看