本篇在讲什么 浅谈对Lua元表和元方法的理解 本篇适合什么 适合初学Lua的小白 本篇需要什么 对Lua语法有简单认知 依赖Lua5.1的环境 依赖Sublime Text3编辑器 本篇的特色 具有全流程的图文教学 重实践,轻理论,快速上手 提供全流程的源码内容 |
★提高阅读体验★ 👉 ♠ 一级标题 👈👉 ♥ 二级标题 👈👉 ♣ 三级标题 👈👉 ♦ 四级标题 👈 |
目录
- ♠ 元表和元方法
- ♥ 元表
- ♥ 获取元表
- ♥ 设置元表
- ♥ 元方法
- ♣ 算数运算相关的元方法
- ♦ 两表相加的简单示例
- ♦ 两组不同数据相加的示例
- ♣ 关系运算相关的元方法
- ♣ 库定义相关的元方法
- ♣ 表相关的元方法
- ♦ __index元方法
- ♦ __newindex元方法
- ♠ 推送
- ♠ 结语
♠ 元表和元方法
个人浅见,元表
就是Lua中对某一个数据或者某一类数据的扩展和补充
,而元方法
就是已经被定义好功能的可被重写的函数
以最常见的表举例:
local t = {}
local t1 = {}
t1.__index = function(_, key)
return tbl[key]
end
setmetatable(t, t1)
print(t[key])
当我们为表t
设置元表t1
后,并在元表t1
中补充__index
元方法,当我们根据键key
从表t中获取数据的时候,如果t中没有,那么就会去拿__index的返回值
下面我们将更细节讨论元表和元方法
♥ 元表
-
元表就是一个表
-
Lua语言中的每一个值(所有类型)都可以有元表
-
每个表(table)和用户数据类型(userdata)都具有各自独立的元表
-
其他类型共享同类型所属的同一个元表(所有字符串
string
共用一个元表) -
新创建的表没有元表
-
字符串都有一个默认的统一元表,其他类型默认没有元表
-
在Lua代码中我们仅能为表(table)添加元表,其他类型可通过c或调试库
注:
一个表还可以成为他自己的元表
♥ 获取元表
t = {}
getmetatable(t)
通过方法getmetatable
获取元表
♥ 设置元表
t = {}
t1 = {}
setmetatable(t, t1)
通过方法setmetatable
将t1设置为t的元表
♥ 元方法
元表为主
定义的各种行为,每个行为都关联对应的元方法,元方法可以简单的分为以下几大类型,我们简答叙述和举例演示
♣ 算数运算相关的元方法
下面表格记录了和算数运算相关的元方法及其功能描述
元方法名 | 功能描述 |
---|---|
__add | 加法 |
__sub | 减法 |
__mul | 乘法 |
__div | 除法 |
__idiv | floor除法 |
__unm | 负数 |
__mod | 取模 |
__pow | 幂运算 |
__band | 与 |
__bor | 或 |
__bxor | 异或 |
__bnot | 取反 |
__shl | 向左移位 |
__shr | 向右移位 |
__concat | 连接运算符 |
♦ 两表相加的简单示例
local t_1 = {1,2,3}
local t_2 = {4,5,6}
local t1 = {}
t1.__add = function(a,b)
local tbl = {}
for k,v in pairs(a) do
table.insert(tbl,v)
end
for k,v in pairs(b) do
table.insert(tbl,v)
end
return tbl
end
setmetatable(t_1, t1)
local result = t_1+t_2
print(result[1],result[2],result[3],result[4],result[5],result[6])
我们来简单分析一下:
- 我们希望两个表通过算数运算符
+
达到一个相加的目的 - 为表
t_1
添加元表t1
- 为元表添加代表相加的元方法
__add
- 执行
t_1+t_2
的操作,我们获取到了一个融合的表
问题剖析一下:
问题1: 为什么只为表t_1
设置了元表
实际上算数类的元方法的执行并不需要二者同时具备
当执行+
的操作时,会按相加顺序从两者中检索__add
元方法
以第一个检索到的元方法为执行方案
二者都没有__add
元方法,则抛异常出来
问题2: 两者融合具体的行为处理
元方法
__add
的参数a和b,即为相加的二者
在方法体内,我们可以自定义融合逻辑
在上述例子中,我们创建新表容纳了参数所有的子集,然后返回
♦ 两组不同数据相加的示例
实际上相加只是一个广义的行为,Lua并不局限于同类型数据之间的操作
存在元方法的情况下,我们可以对任意数据进行相加
的操作
下述例子我们尝试对表(table)
和字符串(string)
相加
local t_1 = {1,2,3}
local t_2 = "aaaaa"
local t1 = {}
t1.__add = function(a,b)
local temp = ""
for k,v in pairs(a) do
temp = temp..v
end
temp = temp .. b
return temp
end
setmetatable(t_1, t1)
print(t_1+t_2)
我们只需要在元方法__add
的方法体内对不同类型的数据做好处理即可
上述例子中我们将表内子集和字符串连接成了一个新字符串作为返回值
注:
其他算数元方法使用方式和例子中的__add
一样
♣ 关系运算相关的元方法
元方法名 | 功能描述 |
---|---|
__eq | 等于 |
__lt | 小于 |
__le | 小于等于 |
Lua的关系运算符其实只有三个分别是:
- 等于(a==b)
- 小于(a<b)
- 小于等于(a<=b)
对于其他三种运算关系,Lua会对其进行转换
- 不等于(a~=b -> not (a==b))
- 大于 (a>b -> b<a)
- 大于等于 (a>=b -> b<=a)
和算数运算有区别:
注:
关系运算二者必须共用相同的元表!!
注:
不同数据只有相等可以比较,但是会一直返回false
注:
不同数据除相等的比较,均会抛出异常
♣ 库定义相关的元方法
程序库在元表中定义和使用它们自己的字段也是一种常见的实践
常见例子1:tostring
我们输出print
时候,会优先检索目标是否包含__tostirng
元方法,如果存在,则会根据方法输出
常见例子2:
可以通过设置元表__metatable
字段,使用户既不能看到也不能修改元表
♣ 表相关的元方法
♦ __index元方法
类似于C#中属性的get方法,获取表值的时候,如果存在该元方法,在不存在对应key值的情况下,回去所求__index
的返回值
♦ __newindex元方法
类似于C#中属性的set方法,在对表赋值的时候,如果key值不存在并且__newindex
存在,则会调用该元方法
注:
我们可以用这两个元方法去制作一些受限制的表,例如只读只写、不能修改的表等等
♠ 推送
- Github
https://github.com/KingSun5
♠ 结语
若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。