• 理解Lua中“元表和元方法“


    小细节 :一般运行lua程序是 lua ./文件名
    但可以在这个lua文件开头加上这句话,则可以直接 ./文件名 就可以执行对应文件
    #!/usr/local/bin/lua

    假设文件名是hello.lua , 则可以直接 ./hello.lua 执行这个文件

    这个路径有可能跟我不一样,要看lua在哪里

    – pairs 和 ipairs的区别
    – ipairs遍历table时,键值从1递增,当键值中断(如[1]过了就是[3])或遇到nil时退出
    – pairs 会遍历表中所有键值对,且元素是根据哈希算法来排序的,所以打印出来的顺序是乱的

    简单说一下什么是元表和元方法

    test = {}
    test.hello = function()
    	print("hha")
    end
    
    • 1
    • 2
    • 3
    • 4

    元表可以绑定在一个普通的表或者一个userdata上, 比如现在有一个普通表test, 当我们正常调用test.hello的时候,可以正常的调用这个函数,但如果我们调用test.world, 我们可以发现,test表中并没有world的对应函数,于是就会去与test表绑定的元表中寻找world函数。

    我上边说的这种情况(找不到world函数),会去test的元表中寻找__index 字段,当然只是上边这种情况会去寻找__index字段对应的处理方式, 还有其他处理方式,后边会一一介绍,__tostring, __call方法等。

    这里我们假设Vector 是一个元表
    Vector = {}
    Vector.__index = Vector
    – 这步必须要,因为Vector是一个元表,当这个元表对应的普通表找不到对应的函数的时候
    – 就会去这个元表(Vector)的__index中查找,这样设置后,__index中就包含元表的所有函数,即整个元表
    – 需要理解一点 __index只是一个元方法,当出现在普通表中找不到函数的情况
    – 就会去找这个普通表对应的元表的__index方法,来进一步寻找,就和__tostring, __call 一样
    – 元方法只是普通表遇到特定情况时的解决方案,所以这种情况下需要设置 元表.__index = 元表

    重点:只是__index 字段是这样设置,__tostring,__call就不是这样设置的,所以需要清楚明白的一点就是,Vector.__index = Vector这样只是为了设置__index元方法这一种元方法,还有很多其他的元方法。

    学习建议:跟着把下边的代码都敲一遍,并且每一个案例都成功运行,就能学懂lua中的元表和元方法。

    所谓的元表和普通表一样,都是table结果,是否作为元表,取决于你自己的操作

    lua中的结构中只有table和userdata可以独立的设置元表

    __index元方法

    这是metatable元表最常用的键了。

    当你通过键来访问table的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的 __index 键。如果 __index 包含一个表格,Lua会在表格中查找相应的键。

    t = {}  --作为普通表		
    mt = {}  --作为元表
    setmetatable(t,mt);-- 会将第二个表设置为第一个参数的表的原表
    getmetatable(t);
    
    t = setmetatable({[2] = 3}, {
        __index = function(t,key)
            if key == "foo" then
                return 0
            else
                return table[key]
            end
        end
    });
    
    other = {foo = 3}
    -- t = setmetatable({}, {__index = other})
    print(t.foo)  -- 0
    print(t.bar)  -- nil
    print(t[2])   --3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    __newindex 元方法

    类似 __index , __newindex 的值为函数或table,用于按键赋值的情况。
    当对一个table中不存在的索引赋值时,解释器就会查找__newindex元方法

    other = {}
    -- setmetatable 会将第二个表设置为第一个参数的表的原表
    -- 并且会将第一个参数的表返回
    t = setmetatable({}, {__newindex = other})
    t.foo = 3
    
    t = setmetatable({}, {
        __newindex = function(t, key, value)
            if type(value) == "number" then
            rawset(t, key, value * value)
        else
            rawset(t, key, value)
        end
    end
    })
    
    t.foo = "foo"
    t.bar = 4
    t.la = 10
    print(t.foo)
    print(t.bar)
    print(t.la)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    __mul 元方法 (乘法)

    t = setmetatable({1,2,3}, {
        __mul = function(t, other)
        new = {}
        
        for i = 1, other do
            for _, v in ipairs(t) do 
            table.insert(new, v) 
            end
        end
    
        return new
    end
    })
    
    t = t * 2 -- 将上边的1,2,3  变成了1,2,3,1,2,3
    for v,k in pairs(t) do
        print(v,k) --这种方式会把key和value一起打印出来   
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    __call 的原方法

    使得你可以像调用函数一样调用table:
    也就是当table名字作为函数名字的时候会被调用
    下边可以观察到,本来t是一个table,却当作函数来使用

    t = setmetatable({}, {
        __call = function(t, a, b, c, whatever)
        return (a +b +c) * whatever
    end
    })
    print(t(1,2,3,4))
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    __tostring的元方法

    – 它可以将一个table转换成字符串,常和print配合使用
    – 如果不使用__tostring元方法,默认的print(表名) 会打印处一串地址

    t = setmetatable({1, 2 ,3}, {
        __tostring = function(t)
            sum = 0
            for _, v in pairs(t) do 
            sum = sum + v 
            end
            return "Sum:"..sum
    end
    })
    
    print(t)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    Springboot基于微信小程序的高校食堂外卖服务毕业设计-附源码200910
    Python - FastAPI 实现 get、post 请求
    从字符串中删除指定字符
    [附源码]计算机毕业设计病人跟踪治疗信息管理系统Springboot程序
    遥感与ChatGPT:科研中的强强联合
    【JavaEE初阶】 JavaScript基础语法——贰
    CVPR 2024 截稿时间
    Linux tail命令:显示文件结尾的内容
    UML建模图文详解教程——类图
    node.js安装及环境配置
  • 原文地址:https://blog.csdn.net/qq_51721904/article/details/126731241