Lua 元表和元方法
一、元表
元表可以修改一个值在面对一个未知操作时的行为,Lua 中使用 table 作为元表的承载。
元表只能给出预先定义的操作集合的行为,比类会更加受限制,不支持继承。
Lua 每一个值都可以有元表 :
- 表和用户数据类型都具有各自独立的元表;
- 其他类型的值则共享对应类型所属的同一个元表;
二、元表的设置
1、类型的原始元表
Lua 中,元表的设置只能针对 table ,其他类型都不能设置。
table 的初始化元表为 nil ,即没有设置元表,只能通过 setmetatable 进行设置,多个 table 可以共享一个 table 作为元表(当然也可以使用他自己作为自己的元表,因为他自身也是一个 table)
Lua 只有 string 初始化了元表,而且是针对了所有的字符串,即 string 都是同一个元表。其他的类型为 nil 。
print("表的初始值", getmetatable({})) --> 表的初始值 nilprint("整型的初始值", getmetatable(10)) --> 整型的初始值 nil
print("浮点型的初始值", getmetatable(10.0)) --> 浮点型的初始值 nil--- 通过打印可以看到两个字符串的元表是同一个
print("字符串的初始值", getmetatable("江澎涌")) --> 字符串的初始值 table: 0x600000b14640
print("字符串的初始值", getmetatable("jiangpengyong")) --> 字符串的初始值 table: 0x600000b14640print("布尔型的初始值", getmetatable(true)) --> 布尔型的初始值 nilprint("nil的初始值", getmetatable(nil)) --> nil的初始值 nilfunction sayHello() end
print("函数的初始值", getmetatable(sayHello)) --> 函数的初始值 nil
2、设置元表和获取元表
2-1、setmetatable(table, metatable)
给表 table 设置元表 metatable
参数
- table:要被设置元表的表
- metabale:元表,如果值为 nil ,则表明要删除 table 的原有元表。如果原来的元表有
__metatable字段,则不能再设置元表,否则会抛出异常cannot change a protected metatable
__metatable会在下面的 “表相关方法” 小节分享
返回值:
返回被设置元表的表,就是参数 table
2-2、getmetatable(object)
如果 object 没有元表,则返回 nil
如果对象 Object 有元表,且该元表有一个 "__metatable" 字段,则返回关联的值。否则,返回给定对象 Object 的元表
2-3、举个例子
local oriTable = {}
local metaTable = {}
print(setmetatable(oriTable, metaTable), oriTable, metaTable) --> table: 0x600001ac0840 table: 0x600001ac0840
print(getmetatable(oriTable), metaTable) --> table: 0x600001ac0900 table: 0x600001ac0900
给元表带有 __metatable 字段的表,设置新的元表,则会抛出异常(见下图)
t2 = { c = 1 }
t2.__metatable = { a = 1 }
s1 = {}
setmetatable(s1, t2)
print('getmetatable(s1)["a"]', getmetatable(s1)["a"]) --> getmetatable(s1)["a"] 1-- 此处会抛出异常:cannot change a protected metatable
print(setmetatable(s1, {}))

三、元表方法
1、具有的元方法
元表方法方法很像 kotlin 中的操作符方法
1-1、算术运算符
| 元表方法 | 含义 |
|---|---|
| __add | 加法 |
| __mul | 乘法 |
| __sub | 减法 |
| __div | 除法 |
| __floor | floor除法 |
| __unm | 负数 |
| __mod | 取模 |
| __pow | 幂运算 |
| __band | 按位与 |
| __bor | 按位或 |
| __bxor | 按位异或 |
| __bnot | 按位取反 |
| __shl | 向左移 |
| __shr | 向右移 |
| __concat | 定义连接运算符 |
1-2、关系运算符
| 元表方法 | 含义 |
|---|---|
| __eq | 等于 |
| __lt | 小于 |
| __le | 小于等于 |
值得注意: ~=、a > b、a >= b 没有对应的元方法,会被转为如下
a ~= b会被转为not( a == b)a > b会被转为b < aa >= b会被转为b <= a
关系运算符遇到两个不同类型的对象,则会直接返回 false ,不会进行搜寻任何的元方法
1-3、库相关方法
| 元表方法 | 含义 |
|---|---|
| __tostring | 当调用 tostring 时,会先检查值是否有一个元方法 __tostring ,有则会先使用。 |
| __metatable | 使用该元方法可以保护元表,用户无法获取也无法修改该元表。当元表设置了 __metatable 的字段,则 getmetatable 会返回这个字段的值,而 setmetatable 则会引发错误 |
| __pairs | 从 Lua 5.2 开始,当元表拥有一个 __pairs 的元方法时,pairs 会调用这个元方法来完成遍历 |
1-4、表相关方法
| 元表方法 | 含义 |
|---|---|
| __index | 一旦访问 table 中不存在的字段,正常情况下会返回 nil 。如果设置了这个元表方法,则会调用自身元表对应的该 __index 元方法,并以被调用的表(即此处的 table ,不是元表)和键作为参,进行调用。也可以给 __index 设置一个 table,这样就会直接在这table 中查询,速度比方法稍快。可以通过 rawget 获取原始数据,不考虑元表。 |
| __newindex | 当调用 table 进行索引赋值时,如果设置了该元表方法,则会使用被调用的表(即此处的 table ,不是元表),键和值作为参,调用该方法。同样也可以给 __newindex 设置一个表,则会将值直接存至该表。可以通过 rawset(talbe, key, value) 相当于 table[key] = value 进行直接对 table 的赋值,不考虑元表。 |
| __len | 获取 table 的长度时,会调用该方法,获取长度 |
__index 和 __newindex 的异同
- 相同点:两个函数都是发生在 table 中没有对应的 key 时触发
- 不同点:当前需要的索引没有对应的值时则调用
__index,如果 table 设置值时,则调用__newindex
2、元方法的搜索
如果两个变量相加,搜索规则如下:
- 先查看第一个值是否有元表,并且是否存在所需元方法,如果存在则使用该元方法,此时第二个值的元方法被忽略。否则进入下一条
- 查看第二个值是否有元表,并且是否存在所需的元方法,如果有则进行使用。否则进入第三条
- 抛出异常
3、举个例子
这里元方法比较多,就不一一粘贴代码了,不然会让文章非常冗长。建议各位童鞋们移步 github clone 下代码自行运行一下会更加深刻理解。
“算术运算符” 、 “关系运算符”、“库相关方法” 相关的代码 可以查看以下的代码:
集合.lua:https://github.com/zincPower/lua_study_2022/blob/master/13%20%E5%85%83%E8%A1%A8%E3%80%81%E5%85%83%E6%96%B9%E6%B3%95/%E9%9B%86%E5%90%88.lua
集合调用.lua:https://github.com/zincPower/lua_study_2022/blob/master/13%20%E5%85%83%E8%A1%A8%E3%80%81%E5%85%83%E6%96%B9%E6%B3%95/%E9%9B%86%E5%90%88%E8%B0%83%E7%94%A8.lua
“表相关方法” 相关的代码
表相关元方法.lua:https://github.com/zincPower/lua_study_2022/blob/master/13%20%E5%85%83%E8%A1%A8%E3%80%81%E5%85%83%E6%96%B9%E6%B3%95/%E8%A1%A8%E7%9B%B8%E5%85%B3%E5%85%83%E6%96%B9%E6%B3%95.lua
四、写在最后
Lua 项目地址:Github传送门 (如果对你有所帮助或喜欢的话,赏个star吧,码字不易,请多多支持)
如果觉得本篇博文对你有所启发或是解决了困惑,点个赞或关注我呀。
公众号搜索 “江澎涌”,更多优质文章会第一时间分享与你。
相关文章:
Lua 元表和元方法
一、元表 元表可以修改一个值在面对一个未知操作时的行为,Lua 中使用 table 作为元表的承载。 元表只能给出预先定义的操作集合的行为,比类会更加受限制,不支持继承。 Lua 每一个值都可以有元表 : 表和用户数据类型都具有各自…...
【Git】01-Git基础
文章目录 Git基础1. 简述1.1 版本管理演变1.2 Git的特点 2. Git安装2.1 安装文档2.1 配置user信息 3. 创建仓库3.1 场景3.2 暂存区和工作区 4. 重命名5. 常用git log版本历史5.1 查看当前分支日志5.2 简洁查看日志5.3 查看最近指定条数的日志 6. 通过图形界面工具查看版本7. 探…...
【Vue2.0源码学习】生命周期篇-初始化阶段(initState)
文章目录 1. 前言2. initState函数分析3. 初始化props3.1 规范化数据3.2 initProps函数分析3.3 validateProp函数分析3.4 getPropDefaultValue函数分析3.5 assertProp函数分析 4. 初始化methods5. 初始化data6. 初始化computed6.1 回顾用法6.2 initComputed函数分析6.3 defineC…...
专升本英语零基础学习
1. 词法 1.1 名词 名词(n.),是词类的一种,属于实词。他表示人,物,事,地点或抽象概念的统一名称。 1.1 名词的含义 名词(n.),是词类的一种,属于实词。他表示人&#x…...
QUIC协议连接详解(二)
目录 一:RTT解释 二:QUIC 1-RTT连接 三:QUIC 0-RTT连接 一:RTT解释 在介绍QUIC协议的连接之前先科普一下什么是RTT。RTT是Round-Trip Time的英文缩写,翻译过来就是一趟来回的时间即往返时延。时间计算即从发送方发送…...
JAVA 经常遇到一些问题【第二部分36~51】
重拾者: 每日记录至目前(记录51种不同场景的问题可参考解决方案) 异常就两部分: 1、excepiton信息: 报错产生的原因 2、at开头表示: 异常产生的代码位置。 欢迎关注本人微信公众号:AIM…...
蓝桥杯打卡Day6
文章目录 N的阶乘基本算术整数查询 一、N的阶乘OI链接 本题思路:本题是关于高精度的模板题。 #pragma GCC optimize(3) #include <bits/stdc.h>constexpr int N1010;std::vector<int> a; std::vector<int> f[N];std::vector<int> mul(in…...
spark集群问题汇总
一、 磁盘问题 问题描述可能原因解决措施core节点磁盘不足, 并且持续增加未开启spark-history的日志清理打开日志清理: spark.history.fs.cleaner.enabled task节点磁盘不足 APP应用使用磁盘过大: 1. 严重的数据倾斜 2. 应用本身数据量大 1. 解决数据倾斜 2. 加大资源, 增加e…...
WebServer 解析HTTP 请求报文
一、TCP 状态转换 浏览器访问网址,TCP传输全过程 二、TCP协议的通信过程 三、TCP 通信流程 // TCP 通信的流程 // 服务器端 (被动接受连接的角色) 1. 创建一个用于监听的套接字- 监听:监听有客户端的连接- 套接字:这…...
Golang开发--interface的使用
在Go语言中,接口(interface)是一种特殊的类型,它定义了一组方法的集合。接口为实现多态性提供了一种机制,允许不同的数据类型实现相同的方法,从而可以以统一的方式处理这些不同类型的对象。接口在Go中广泛用…...
2023 年高教社杯全国大学生数学建模竞赛题目 B 题 多波束测线问题
B 题 多波束测线问题 单波束测深是利用声波在水中的传播特性来测量水体深度的技术。声波在均匀介质中作匀速直线传播,在不同界面上产生反射,利用这一原理,从测量船换能器垂直向海底发射声波信号,并记录从声波发射到信号接收的传播…...
leetcode算法题--生成特殊数字的最少操作
原题链接:https://leetcode.cn/problems/minimum-operations-to-make-a-special-number/description/ 感觉还是比较难想到的。。 func minimumOperations(num string) int {res : len(num)if strings.Contains(num, "0") {res-- }f : func(tail string)…...
数学建模--决策树的预测模型的Python实现
目录 1.算法流程简介 2.算法核心代码 3.算法效果展示 1.算法流程简介 """ 决策树的应用:对泰坦尼克号数据集成员进行预测生死 算法流程还是比较简单的,简单学习一下决策树跟着注释写即可 文章参考:https://zhuanlan.zhihu.com/p/133838427 算法种遇上sklear…...
Linkstech多核并行仿真丨光伏发电系统模型及IEEE 39 bus模型多核并行实测
新能源场站和区域电网作为复杂且具有动态特性的大规模电力系统,需要实时仿真测试来验证其性能、稳定性和响应能力。在这种背景下,多核并行仿真运算显得尤为重要。多核并行仿真能够同时处理电力系统的复杂模型,加速仿真过程,实现接…...
在STS里使用Gradle编译Apache POI5.0.0
1、到官方下面地址下载Gradle最新的版本 Gradle Distributions 2、解压后拷贝到D盘下D:\gradle-8.3-rc-4里 3、配置环境变量 新建系统变量 GRADLE_HOME ,值为 路径 4、在 Path 中添加上面目录的 bin 文件路径 (可以用 %GRADLE_HOME%\bin,…...
golang - 使用有缓冲通道控制并发数
在 Go 语言中,使用带缓冲的通道(buffered channels)可以有效地控制并发数。带缓冲的通道可以让你限制同时运行的 goroutine 数量,从而避免过度并发导致的资源耗尽问题。以下是一个使用带缓冲通道控制并发数的示例: pa…...
AUTOSAR测试指标
测试方法 1、测试相关时间2、检查各个状态下ECU的情况3、程序编写 1、测试相关时间 序号时间参数描述测试方法时间1T_Wakeup从睡眠模式到网络模式,(上位机)发送NM报文的时间唤醒源的时间100ms2T_START_NM从睡眠模式到网络模式,DUT发送的第一帧NM报文捕获…...
Vue 前端项目使用alibaba矢量库svg图标
Vue 前端项目使用alibaba矢量库svg图标 这里主要是记录 vue项目中使用阿里矢量库图标的操作流程,方便以后查阅!!! 一、简介 iconfont 是由阿里巴巴体验团队打造的,一款设计和前端开发的便捷工具.拥有着很强大且图标内…...
蓝桥杯官网填空题(距离和)
题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 两个字母之间的距离定义为它们在字母表中位置的距离。例如 A 和 C 的距离为 2,L 和 Q 的距离为 5。 对于一个字符串,我们称字符串中两两字符…...
【座位调整】Python 实现-附ChatGPT解析
疫情期间课堂的座位进行了特殊的调整,不能出现两个同学紧挨着,必须隔至少一个空位,给你一个整数数组desk,表示当前座位的占座情况,由若于0和1组成,其中 0 表示没有占位,1表示占位。在不改变原有座位秩序情况下,还能安排坐几个人? 输入描述: 第一行是一个数组,表示作为…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果 {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
webpack面试题
面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...
