• 用继承的思想理解lua元表


    众所周知,lua最最核心的数据结构是table,是一个key-value hash表,可以用t.key或t[key]来查询。当key值不存在时,一般的hash表返回空值,但lua的table在一定条件下会触发元方法,在设置的元表table里继续查找,如果查到了,则返回元表里的值而不是空值。

    跟继承类似:

    A继承B,A:XXX(),如果A中没有此方法,则继续在B中查找
    设置A的元表是B,A.key,如果A中没有key,在一定条件下到B中查找

    1. lua查找元素的过程

    local mt = {a = "mt"}
    mt.__index = mt
    local t = setmetatable({}, mt)
    print("---------> ", t.a)   ---> mt

    t.a,在表t中查找"a",不存在,如果t设置了元表,并且元表设置了__index域,则在元表设置的__index域mt中继续查找,即返回mt。如果没有设置元表返回nil。如果元表没有设置__index域也返回nil。如果在mt没找到,继续在mt的元表中继续查找,以此类推

    local mt1 = {a = "mt1"}
    mt1.__index = mt1
    local mt2 = setmetatable({}, mt1)
    mt2.__index = mt2
    local mt = setmetatable({}, mt2)
    print(mt.a, mt2.a, mt1.a)    ----> mt1 mt1 mt1

    2. lua实现类

    lua中并没有类的概念,但根据元表的特性很容易实现一个类。即设置obj表的元表为class表。有很多不同的实现思路,以下是一个常用的模板:

    local class = {}
    class.__index = class
    
    function class.New(cls, name)
        local self = setmetatable({}, cls)
        self.name = name
        return self
    end
    
    function class:print()
        print("name = ", self.name)
    end
    
    
    local obj = class:New("abc")
    obj:print()     ---> name = abc

    3.lua实现继承

    利用元表的特性,设置子类的元表为父类,当在子类找不到时,在父类中继续查找。

    local base = {}
    base.__index = base
    
    function base.New(cls, name)
        local self = setmetatable({}, cls)
        self.name = name
        return self
    end
    
    function base:print()
        print("name = ", self.name)
    end
    
    
    local class = setmetatable({}, base)
    class.__index = class
    
    function class.New(cls, name, age)
        local self = base.New(cls, name)
        self.age = age
        return self
    end
    
    function class:print2()
        self:print()
        print("age = ", self.age)
    end
    
    
    local obj = class:New("abc", 10)
    obj:print2()             ---> name = abc   age =10

    4. lua的元表和元方法

    lua的元表和元方法自定义一系列的操作集合,除了查找元素__index域外,还有__newindex, __gc, __tostring, __add等操作,详见http://cloudwu.github.io/lua53doc/manual.html

    local mt = {
        __tostring = function(t)
            local s=""
            for _, v in ipairs(t) do
                s = s .. v .. ","
            end
            return s
        end,
        __add = function(t1, t2)
            local t = {}
            for i, v in ipairs(t1) do
                t[i] = v
            end
            for i, v in ipairs(t2) do
                t[i] = (t[i] or 0) + v
            end
            return t
        end,
    }
    
    local t = setmetatable({1,2,3,4,5}, mt)
    print(t)      ---> 1,2,3,4,5
    
    local t1 = setmetatable({1,2,3}, mt)
    local t2 = setmetatable({10,20,30,40,50}, mt)
    local t3 = setmetatable(t1+t2, mt)
    print(t3)     ---> 11,22,33,40,50

    注:如果用rawget(t, key),rawset(t, key, value),是不会触发元方法的,只在t中操作

  • 相关阅读:
    Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (gbk_chinese_ci,COERCIBLE) for operation '=' 一个解决办法(转载)
    mysql limit用法
    preparedStatement一个小技巧
    两个简单的压力测试代码。
    cookie实现session机制
    java.util.properties用法
    数据库是否使用外键,及视图,索引,存储过程的一些说明(zz)
    某项目要调用现有的100多个DLL 二 最最简单原型的思考
    面试题:红绿灯
    一个简单的封装 .net的日志功能
  • 原文地址:https://www.cnblogs.com/RainRill/p/7590950.html
Copyright © 2020-2023  润新知