美文网首页
Lua中元表的学习

Lua中元表的学习

作者: 我家菇凉 | 来源:发表于2021-07-08 14:40 被阅读0次

Lua本身没有面向对象的思想,但是可以根据表、元表、元方法来靠近它

一、元表与元方法的概念
Lua中每个值都可具有元表。元表是普通的Lua表,定义了原始值在某些特定操作下 的行为。例如,当table作为加法的操作数时,Lua检查其元表中的”__add”字段是否有 个函数。如果有,Lua调用它执行加法。我们称元表中的键为事件(event),称值为 元方法(metamethod)。
前述例子中的事件是”add”,元方法是执行加法的函数。

Lua创建新的table的同时不会创建元表
t={}
print(getmetatable(t)) –>nil 可以使用setmetatable(t,t1)给t设置元表为t1。
在Lua中,只能设置table的元表。
若要设置其他类型的元表,则必须通过C代码来完成。

元表可以想象成类,表是元表的子类
元表 :定义某些特定行为的操作 t1+t2 t1-t2
元表: 就是一个普通的表(table)t = {}
t1 + t2 : 程序会到t1 t2 中查找元表,再在元表中查找 __add
如果有 __add ,就会执行对应的方法,如果没有,程序报错
像 元表的__add方法就是元方法

二、设置元表
设置元表 setmetatable , 给表设置一个元表
获取元表 getmetatable ,得到元表的地址

local mt = {}
--Lua创建新的table的同时不会创建元表
t={}
print(getmetatable(t)) -->nil
1
2
3
4
local mt = {}
local t = {}
setmetatable(t,mt) -- 给表t设置元表mt
print(mt) -- 打印地址 ,
print(getmetatable(t)) --获取元表 打印元表地址,它们的地址相同
1
2
3
4
5
三、元方法 __add
表之间可以进行运算符计算,但是需要表有元表,元表有对应的元方法,否则报错
并且注意元方法使用了两个下划线作前缀

local mt = {}

mt.__add = function(Lhs,Rhs)
print(Lhs)
print(Rhs)
return "abc"
end

local t1 = {}
local t2 = {}
setmetatable(t1,mt)
setmetatable(t2,mt)

print("t1的地址:")
print(t1)
print("t2的地址:")
print(t2) --t1 和 t2 的地址不同

local result = t1 + t2 --有在元表上写了 __add方法就可以表之间可相加,相加时调用元表
print(result) -- abc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
__add方法可以看成是运算符重载的加法运算,里面传入左右两个元表,
最后只能返回一个(元表、表达式、值,不返回也可以),多了会以nil值返回

四、其他元方法
__add:加法
__sub:减法
__mul:乘法
__div:除法
__unm:相反数
__mod:取模
__pow:乘幂
具体的使用方式和add类似,不再详细叙述。

关系类的元方法
除了加法减法这些算术类的操作之外,大于小于等这些关系类的操作也是有元方法的:
__eq:等于
__lt:小于
__le:小于等于
如果对两个具备不同元表的值进行这些比较操作,就会报错,一定要注意,这和加减法
的规则不一样。

五、注意表和元表关系的区分
两个具有不同元表的值进行算术操作(比如加法)之前举例的时候,两个table相加, 这两个table都是具有相同的元表的,所以没有任何问题。
那么,如果两个table或者两个进行相加操作的值,具有不同的元表呢?
相同元表:执行元表中的元方法
不同元表:第一个值有元表(操作符前面),就以这个元表为准看是否有元方法,
如果没有就看第二个元表是否有元方法。
都没有元方法就会报错

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 = {}

setmetatable(t1,mt1) -- 设置mt1为t1(普通表)的元表
setmetatable(t2,mt2) -- 设置mt2为t2(普遍表)的元表

local result = t1 - t2 --计算过程中调用元表的mt1.__sub元方法
print(result) --nil

local result2 = t2 - t1 --计算过程中调用元表的mt2.__sub元方法
print(result2) --nil
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
我们再来理清下关系:
mt1 和 mt2 是元表 因为使用setmetatable方法设置了 setmetatable(t1,mt1) setmetatable(t2,mt2)
而 t1 和 t2 是普通的表,要使用普通的表来计算 ,而元方法在它们的元表中,在普通的表进行运算的时候元方法会(进行选择后)自动调用

六、__index 查询
如果访问表中不存在的字段->到元表中查找 __index
设想一下,当我们获取一个table中不存在的元素的时候。默认的返回nil,但是,如果我们不希望这样呢?我们希望在访问不存在的字段时,进行一些自定义的操作呢?没问题,Lua满足了我们,那就是,__index元方法。在使用加法操作时,会查找__add元 方法。那么,在调用table不存在的字段时,会调用__index元方法,这是一样的规则。

__index是一个函数
local mt = {}
mt.__index = function(table,key)
print("元表中的index")
print(table) -- 打印t表
print(key) -- 打印name
end

local t = {}
setmetatable(t,mt)

print(t,mt) --可以找到table: 0x7f997bc07a70 table: 0x7f997bc04d50
print(t.name) --t表不可以找到,调用元表的__index函数,
1
2
3
4
5
6
7
8
9
10
11
12
13
__index是一个表
local k = {name = "Y" , age = 23 }
local mt = {
__index = k-- index对应为表
}

local t = {sex = "boy"}
setmetatable(t,mt)
print(t.sex) --可以在index对应表中找到就打印出值
print(t.name)
print(t.enjoy) -- 元表index对应的表中也不存在该字段,打印nil
1
2
3
4
5
6
7
8
9
10
表中内容带有函数
local k = {
name = "Y",
age = 23,
SayHello = function()
print("Hello")
end,
Bye = function()
print("Bye")
end
}

local mt = {
__index = k
}
local t = {}
setmetatable(t,mt) --设置mt为t的元表
print(t.name) --可以从元表的__idex对应的k表找到值,打印 Y
t.SayHello() -- 可以从元表的__idex对应的k表找到方法,调用打印出 Hello
t.Bye() -- 如果写错方法名(或元表也没有)则报错,这里可以找到,直接调用k表的Bye方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
七、__newindex的使用
有的时候我们要对table中某个不存在的字段赋值。没错,我们直接就能赋值了, 不会报错的。但是有的时候我想监控这个操作,如果有人想对table不存在的字段进 行赋值的时候,我想进行一些额外的处理呢?
这时候就要用到__newindex。
大家要记住这句话:__index用于查询,__newindex用于更新
查询找的是__index ,修改找的是__newindex

__newindex的规则:
a.如果__newindex是一个函数,则在给table不存在的字段赋值时,会调用这个函数。
b.如果__newindex是一个table,则在给table不存在的字段赋值时,会直接给__newindex的table赋值。
如果发现没有调用,可能是写错了,记得是要两个下划线~

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

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
如上的 t.age 不存在,则会在表中增加一个

__newindex是一个函数
如果普通表没该变量,则元表会调用_newindex函数,但是不会给元表赋值

local mt = {
__newindex = function(table,key,value)
print(table)
print(key)
print(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
__newindex是一个表
如果普通表没有该变量,那么到元表查找,并在元表新增或修改变量值

local k = {name = "Y"}
local mt ={
__newindex = k
}

local t = {}
setmetatable(t,mt)
print(t.name) -- nil 查询
print(k.name) -- Y 查询
print(t.name) -- nil 查询
t.name = "YY" -- 到对应的k表 修改
print(k.name) -- YY 查询
print(t.name) -- nil 查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
__index 和 __newindex的使用
local smartman = {name = "none"}
local other = {name = "cc"}
local mt = {
__index = smartman,
__newindex = other
}
local t = {}
setmetatable(t,mt)
print("other赋值前的name = ".. other.name) --cc
print("t赋值前 : ".. t.name) -- 原表不变 none
t.name = "superman"
print("other修改后name = " .. other.name) --newindex对应的表数值修改 --superman
print("t修改后 : ".. t.name) -- 原表不变 -- none
1
2
3
4
5
6
7
8
9
10
11
12
13
smartman表对应__index只是用来查询,本身并没有变化,变化修改的是newindex对应的other表

八、忽略元表的操作rawget rawset
local mt = {
__index = function (table,key)
print("元表中的查找功能")
end,
__newindex = function()
print("元表中的修改功能")
end
}
local t = {}
setmetatable(t,mt)
print(t.name) -- nil 不忽略元表的功能
print(rawget(t,"name"))-- 查找 忽略元表的功能,不会调用元表的__index对应的方法
rawset(t,"name","YYY") -- 修改 忽略元表的功能,不会调用元表的__newindex对应的方法,
--即在t表添加name = "YYY"
print(t.name) --YYY

相关文章

  • Lua中元表的学习

    Lua本身没有面向对象的思想,但是可以根据表、元表、元方法来靠近它 一、元表与元方法的概念Lua中每个值都可具有元...

  • Lua 元表(Metatable)

    学习网站Lua 元表(Metatable)

  • Lua学习

    Lua 学习 元表 setmetatable(table,metatable): 对指定table设置元表(met...

  • 2017.5.26

    lua学习:metatable 元方法,元表 lua 中的任何一个值都有其预定义的一套操作,这些操作都是在元表中定...

  • 2018-03-26 lua中元表简介

    Lua中提供的元表是用于帮助Lua数据变量完成某些非预定义功能的个性化行为,如两个table的相加。假设a和b都是...

  • Lua 实现面向对象 (原创)

    要理解Lua是如何实现面向对象的。首先要熟悉Lua元表的相关知识,可以阅读我上一篇文章《Lua元表 (Metata...

  • 学习常用链接

    //Lua Lua table详解 Lua 元表详解 云风博客 //Unity Unity知识点 栈和队列 Uni...

  • Lua实现继承的方法

    lua通过元表实现继承 lua查找一个表元素的规则如下 1.在表中查找,如果找到,则返回这个元素 2.判断该表是否...

  • 数据结构总结

    1.表 1.1 线性表 线性表的特点是 · 表中元素个数有限 · 元素具有逻辑上的顺序性 · 表中元素的数据类型相...

  • Lua元表

    Lua元表 在Lua中,我们可以通过key找到对应的value值,但是无法对两个table进行操作。 在Lua中为...

网友评论

      本文标题:Lua中元表的学习

      本文链接:https://www.haomeiwen.com/subject/ubctpltx.html