Lua学习记录(6) --- Lua中的元表相关内容

目录

一、Lua中的元表的作用以及设计理念

二、关于元表的操作

(1)设置一个表为另一个表的元表

(2)__tostring方法的介绍

(3)__call方法的介绍

(4)一堆运算符的重载

[(5)__index的介绍 这个很重要](#(5)__index的介绍 这个很重要)

(6)__newindex的介绍

[(7)针对上面两种设计 还有反他们的设计 主要都是为了不时之需 那就是 rawget 和 rawset](#(7)针对上面两种设计 还有反他们的设计 主要都是为了不时之需 那就是 rawget 和 rawset)


一、Lua中的元表的作用以及设计理念

元表(metatable)是 Lua 里赋予表"扩展行为"的机制。因为 Lua 只有 table 这一种复合数据结构,官方希望在不引入复杂类型系统的前提下,也能做到运算符重载、自定义索引、对象模型等能力,所以设计了"把额外规则存进元表"的办法。任何 table 都可以附着一张元表;Lua 遇到无法直接处理的操作(例如对不存在的键取值、两个表相加、把 table 当函数调用)时,就去检查元表里对应的"元方法"(如 __index、__add、__call,这里具体的我们后面讲),如果存在就按你定义的逻辑来执行。

概念上,元表就是"描述某个 table 特殊行为的表"。它本身也是普通 table,只是被 Lua 引擎当作当前表的"说明书"。

其实元表也是一张表,当你对当前表的一些操作无法得到满足的时候 会去对你的元表有一定操作。

元表的初衷是:让简单的 table 也能拥有"像别的语言里类/对象那样的可定制行为",为 Lua 的灵活性和简洁语法提供底层支撑。

二、关于元表的操作

(1)设置一个表为另一个表的元表

很简单 申明两个表 然后用一个setmetatable(被设置表,元表)就完了

Lua 复制代码
-- 设置元表
meta = {}
myTable = {}
-- 设置元表函数
-- 第一个参数 子表 第二个参数 子表的元表
setmetatable(myTable, meta)

(2)__tostring方法的介绍

这个是什么呢?这个是 如果你有一个子表 你想对他进行打印操作 比如print(mytable) 如果有元表 那么就会执行 元表中的这个函数 不过这个函数默认是空的 需要我们自己写内容 比如:

不设置元表情况 设置元表情况

无参数情况 有参数情况

有一点需要注意的是 你可以将子表作为参数传进去

(3)__call方法的介绍

这个很简单 如果把子表当成函数调用时候 会调用执行这个call方法

这里解释一下第一个 true哪里来的 刚刚我们说了 如果设置了元表的子表有打印行为就会执行元表的__tostring()函数 这里就是这么来的

这个也是一样 默认传入的第一个参数就是子表

(4)一堆运算符的重载

不难 原理同上 下面是栗子🌰!值得关注的是 必须是同一元表 相加才有意义 不然没用还可能报错

Lua 复制代码
meta4 = {
    -- 相当于运算符重载 当子表使用+运算符时 会调用该方法
    -- 运算符+
    __add = function (t1,t2)
        return t1.age + t2.age
    end,
    -- 运算符-
    __sub = function (t1,t2)
        return t1.age - t2.age
    end,
    -- 运算符*
    __mul = function (t1,t2)
        return t1.age * t2.age
    end,
    -- 运算符/
    __div = function (t1,t2)
        return t1.age / t2.age
    end,
    -- 运算符%
    __mod = function (t1,t2)
        return t1.age % t2.age
    end,
    -- 运算符^
    __pow = function (t1,t2)
        return t1.age ^ t2.age
    end,
    -- 运算符==
    __eq = function (t1,t2)
        return t1.age == t2.age
    end,
    -- 运算符<
    __lt = function (t1,t2)
        return t1.age < t2.age
    end,
    -- 运算符<=
    __le = function (t1,t2)
        return t1.age <= t2.age
    end,
    -- 运算符..
    __concat = function (t1,t2)
        return tostring(t1.age)..tostring(t2.age)
    end
}
myTable4 = {
    age = 10
}
setmetatable(myTable4,meta4)

myTable5 = {
    age = 2
}
setmetatable(myTable5,meta4)
print(myTable4 + myTable5) -- 12
print(myTable4 - myTable5) -- 8
print(myTable4 * myTable5) -- 20
print(myTable4 / myTable5) -- 5
print(myTable4 % myTable5) -- 0
print(myTable4 ^ myTable5) -- 100
print(myTable4 == myTable5) -- false
print(myTable4 < myTable5) -- false
print(myTable4 <= myTable5) -- false
print(myTable4 .. myTable5) -- 102
-- -- 注意 ! 如果要用条件运算符 来比较两个对象
-- -- 那么这两个对象的原表一定要一致 才能准确调用重载的运算符 不然没用

(5)__index的介绍 这个很重要

这个的作用针对的是表中字段的查找操作

这个的作用就是 如果你在你当前表查找某个元素 而你这个表没有这个元素的话 那么就会到你的元表指定的__index的表进行元素的查找 及比如 子表A 的元表metaA的__index指向的表为 F。 F中有一个字段为 M。A表没有,如果我直接访问A.M那么这个肯定是nil的 ,如果我设置了A 的元表metaA的__index为F的话 那么就可以获取到这个字段了

记住啊 是到元表指定的表 而不是找不到元素来元表找

说白了 就是找不到东西会到原表指定表中继续查找 对于后面的面向对象中很有用

Lua 复制代码
-- __index的作用就是 当子表中找不到某个属性时候
-- 会到原表中__index指定的表中去寻找对应的属性
-- 如果找不到的话 就为空了
meta6 = {
    name = "元表的名字"
}
myTable6 = {
   -- name = "子表的名字"
}
-- 这个index一般写在表外面 内部可能会出现奇怪的问题 不知道有什么问题 我也看到过写里面的 
-- 这个index的查找可以一层层的往上找 一定是找__index指向的表
meta6.__index = {name = "12345"}
 setmetatable(myTable6,meta6)
print(myTable6.name)

(6)__newindex的介绍

这个的作用针对的是给表中字段赋值操作 如果给表中不存在字段赋值的话 会将这个字段转移到 你的元表的 __newindex指向的表中 创建这样一个字段然后赋值

触发时机:对表 t 写入一个目前不存在的 key 时(例如 t.x = 10 且 t.x == nil),Lua 会检查 t 的元表,如果定义了 __newindex 则改由它处理赋值

Lua 复制代码
-- newindex 当一个表中的属性赋值的时候 这个属性不存在的话
-- 那么会把这个值赋值到newindex所指的表中 不会修改自己
meta7 = {

}
meta7.__newindex = meta7
myTable7 = {

}
setmetatable(myTable7,meta7)
myTable7.age = 1000
print(myTable7.age)
print(meta7.age)

(7)针对上面两种设计 还有反他们的设计 主要都是为了不时之需 那就是 rawget 和 rawset

rawget 当我们使用这个函数时 会去找自己身上有没有这个变量 忽略index的设计

rawset 该方法会忽略newindex的设置 只会改自己的表中的变量

还有个小方法 获取自己的元表是谁 getmetatable(表)

写完收工 明日再见

相关推荐
Scott9999HH7 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社8 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海8 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖9 小时前
JDK 26 新特性详解
java·开发语言
马优晨9 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
a11177611 小时前
2FA 验证码生成器(github登录验证 app)
笔记·学习
我的xiaodoujiao11 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest
人邮异步社区11 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大12 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai12 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang