• Lua 元表和元方法


    1. 元表(Metatable)

    元表是普通的Lua表,定义了原始值在某些特定操作下的行为。
    我们称元表中的键为事件,称值为元方法
    设置(SetMetatable)/获取(GetMetatable)元表:
    SetMetatable 的两种写法:

    local mt = {}
    setMetatable(t, mt)
    
    setMetatable(t, {__add = function() end})
    
    • 1
    • 2
    • 3
    • 4
    local mt = {}
    local t = {}
    print(getmetatable(t))          // nil
    setmetatable(t, mt)             // 设置表 t 的元表为 mt
    print(mt)
    print(getmetatable(t))          // 获取元表地址 和上面打印的 mt 地址相同
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出结果:

    nil
    table: 000001ECD17E3940
    table: 000001ECD17E3940
    
    • 1
    • 2
    • 3

    2. 元方法

    2.1 __add(对表进行"+"操作时触发)

    local mt = {}
    
    mt.__add = function(tab1, tab2)
        local resTab = {}
    
        local len = math.max(#tab1, #tab2)
    
        if len == 0 then return resTab end
        for i = 1, len, 1 do
            if type(tab1[i]) == "nil" then tab1[i] = 0 end
            if type(tab2[i]) == "nil" then tab2[i] = 0 end
    
            resTab[i] = tab1[i] + tab2[i]
        end
    
        return resTab
    end
    
    local tab1 = {1, 2, 3}
    local tab2 = {4, 5, 6}
    
    setmetatable(tab1, mt)
    setmetatable(tab2, mt)
    
    local resTab = tab1 + tab2
    
    for index, value in ipairs(resTab) do
        print(value)
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    输出结果:

    5
    7
    9
    
    • 1
    • 2
    • 3

    2.1.1 其它操作符的方法

    元方法对应运算符
    __add+
    __sub-
    __mul*
    __div/
    __mod%
    __concat…(连接符)
    __eq==
    __lt<
    __le<=

    2.2.2 注意事项

    当涉及二元操作符时:两表元表有以下情况

    • 相同元表:执行元表中的元方法
    • 不同元表:第一个值有元表(操作符前面),就以这个元表为准看是否有元方法,
      如果没有就看第二个元表是否有元方法。
    • 都没有元表:报错
    local mt1 = {}
    local mt2 = {}
    
    mt1.__sub = function(t1,t2)
        print("mt1->sub")
    end
    
    mt2.__sub = function(t1,t2)
        print("mt2->sub")
    end
    
    local t1 = {}
    local t2 = {}
    local t3 = {}
    
    setmetatable(t1,mt1)    -- 设置mt1为t1(普通表)的元表
    setmetatable(t2,mt2)    -- 设置mt2为t2(普遍表)的元表
    
    local res1 = t1 - t2    -- 计算过程中调用元表的mt1.__sub元方法 mt1->sub
    
    local res2 = t2 - t1    -- 计算过程中调用元表的mt2.__sub元方法 mt2->sub
    
    local res3 = t3 - t1    -- 由于t3没有元表 __sub元方法,所以调用t1的元表中的元方法 mt1->sub
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2.2 __tostring (print()时触发)

    local mt = {}
    
    mt.__tostring = function(tab)
        local str = ""
        for index, value in pairs(tab) do
            str = str .. index .. "--" .. value .. "\n"
        end
    
        return str
    end
    
    local tab = {1, 2, 3}
    
    setmetatable(tab, mt)
    
    print(tab)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    输出结果:

    1--1
    2--2
    3--3
    
    • 1
    • 2
    • 3

    2.3 __index (访问表中不存在属性时触发)

    1. __index 是一个表

    local mt = {}
    mt.__index = {sex = "boy"}
    
    local tab = {name = "ming", age = 18}
    
    print(tab.name, tab.age)    -- ming 18
    print(tab.sex)          -- nil
    
    setmetatable(tab, mt)
    
    print(tab.sex)          -- boy
    print(tab.enjoy)        -- nil
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2. __index 是一个函数

    local mt = {}
    mt.__index = function(table,key)
        print(table) -- 打印t表
        print(key) -- 打印name
    end
    
    local t = {}
    setmetatable(t,mt)
    
    print(t.name) -- t表不可以找到,调用元表的 __index 元方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    输出结果:

    table: 0000026EFEE9F4C0
    name
    nil
    
    • 1
    • 2
    • 3

    2.4 __newindex(对table中不存在的字段赋值时调用)

    1. 普通表修改键值
    存在则修改,不存在就会增加

    local t = {name = "Y"}
    t.name = "YY" -- 修改
    t.age = 23	  -- 添加
    
    for key , value in pairs(t) do --无序遍历字典类型表
        print(key .. " : " .. value)
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出结果:

    age : 23
    name : YY
    
    • 1
    • 2

    2.__newindex是一个函数
    调用_newindex函数,但是不会给元表赋值

    local mt = {}
    
    mt.__newindex = function(table, key, value)
        print(table)
        print("key:" .. key)
        print("value:" .. value)
        end
    
    local t = {}
    setmetatable(t,mt)
    
    print(t.name) -- nil
    t.name = "YY" 
    print(t.name) -- 赋值后 先调用__newindex函数然后打印 nil
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    输出结果:

    nil
    table: 0000012C2529F5F0
    key:name
    value:YY
    nil
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.__newindex是一个表
    如果普通表没有该变量,那么到元表查找,并在元表新增或修改变量值

    local k = {name = "ming"}
    local mt ={}
    mt.__newindex = k
    
    local t = {}
    setmetatable(t,mt)
    print(t.name) -- nil  查询
    print(k.name) -- Y    查询
    
    t.name = "YY" -- 到对应的k表 修改
    print(k.name) -- YY   查询  
    print(t.name) -- nil  查询
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    输出结果:

    nil
    ming
    YY
    nil
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    想要精通算法和SQL的成长之路 - 最长等差数列
    C#,入门教程——解决方案资源管理器,代码文件与文件夹的管理工具
    Web端和App端测试小结
    ABAP 选择屏幕多页签
    解锁精准营销的秘密武器:数据利器助您实现业务增长
    通达OA与think PHP对接
    Meta 内部都在用的 FX 工具大起底:利用 Graph Transformation 优化 PyTorch 模型
    Unirech阿里云国际版云服务器代充-使用Python批量创建实例
    Netty 入门
    电脑每次开机杀毒软件报iusb3mon.exe病毒已清除,电脑中病毒iusbmon杀毒办法,工具杀毒
  • 原文地址:https://blog.csdn.net/weixin_45136016/article/details/128120088