Lua的元表和元方法

1. 元表(Metatable)

元表是普通的Lua表,定义了原始值在某些特定操作下的行为。

我们称元表中的键为事件,称值为元方法。

设置(SetMetatable)/获取(GetMetatable)元表:

SetMetatable 的两种写法:

lua 复制代码
local mt = {}
setMetatable(t, mt)

setMetatable(t, {__add = function() end})
lua 复制代码
local mt = {}
local t = {}
print(getmetatable(t))          // nil
setmetatable(t, mt)             // 设置表 t 的元表为 mt
print(mt)
print(getmetatable(t))          // 获取元表地址 和上面打印的 mt 地址相同

输出结果:

lua 复制代码
nil
table: 000001ECD17E3940
table: 000001ECD17E3940

2. 元方法

2.1 __add(对表进行"+"操作时触发)

lua 复制代码
local mt = {}

mt.__add = function(tab1, tab2)
    local resTab = {}

    local len = math.max(#tab1, #tab2)

    if len == 0 then return resTab end
    for i = 1, len, 1 do
        if type(tab1[i]) == "nil" then tab1[i] = 0 end
        if type(tab2[i]) == "nil" then tab2[i] = 0 end

        resTab[i] = tab1[i] + tab2[i]
    end

    return resTab
end

local tab1 = {1, 2, 3}
local tab2 = {4, 5, 6}

setmetatable(tab1, mt)
setmetatable(tab2, mt)

local resTab = tab1 + tab2

for index, value in ipairs(resTab) do
    print(value)
end

输出结果:

lua 复制代码
5
7
9
元方法 对应运算符
__add +
__sub -
__mul *
__div /
__mod %
__concat ...(连接符)
__eq ==
__lt <
__le <=

注意事项

当涉及二元操作符时:两表元表有以下情况

  • 相同元表:执行元表中的元方法
  • 不同元表:第一个值有元表(操作符前面),就以这个元表为准看是否有元方法, 如果没有就看第二个元表是否有元方法。 都没有元表:报错
lua 复制代码
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 = {}
local t3 = {}

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

local res1 = t1 - t2    -- 计算过程中调用元表的mt1.__sub元方法 mt1->sub

local res2 = t2 - t1    -- 计算过程中调用元表的mt2.__sub元方法 mt2->sub

local res3 = t3 - t1    -- 由于t3没有元表 __sub元方法,所以调用t1的元表中的元方法 mt1->sub

2.2 __tostring (print()时触发)

lua 复制代码
local mt = {}

mt.__tostring = function(tab)
    local str = ""
    for index, value in pairs(tab) do
        str = str .. index .. "--" .. value .. "\n"
    end

    return str
end

local tab = {1, 2, 3}

setmetatable(tab, mt)

print(tab)

输出结果:

lua 复制代码
1--1
2--2
3--3

2.3 __index (访问表中不存在属性时触发)

  1. __index 是一个表
lua 复制代码
local mt = {}
mt.__index = {sex = "boy"}

local tab = {name = "ming", age = 18}

print(tab.name, tab.age)    -- ming 18
print(tab.sex)          -- nil

setmetatable(tab, mt)

print(tab.sex)          -- boy
print(tab.enjoy)        -- nil
  1. __index 是一个函数
lua 复制代码
local mt = {}
mt.__index = function(table,key)
    print(table) -- 打印t表
    print(key) -- 打印name
end

local t = {}
setmetatable(t,mt)

print(t.name) -- t表不可以找到,调用元表的 __index 元方法

输出结果:

lua 复制代码
table: 0000026EFEE9F4C0
name
nil

2.4 __newindex(对table中不存在的字段赋值时调用)

  1. 普通表修改键值
    存在则修改,不存在就会增加
lua 复制代码
local t = {name = "Y"}
t.name = "YY" -- 修改
t.age = 23	  -- 添加

for key , value in pairs(t) do --无序遍历字典类型表
    print(key .. " : " .. value)
end

输出结果:

lua 复制代码
age : 23
name : YY

2.__newindex是一个函数

调用_newindex函数,但是不会给元表赋值

lua 复制代码
local mt = {}

mt.__newindex = function(table, key, value)
    print(table)
    print("key:" .. key)
    print("value:" .. value)
    end

local t = {}
setmetatable(t,mt)

print(t.name) -- nil
t.name = "YY" 
print(t.name) -- 赋值后 先调用__newindex函数然后打印 nil

输出结果:

lua 复制代码
nil
table: 0000012C2529F5F0
key:name
value:YY
nil

3.__newindex是一个表

如果普通表没有该变量,那么到元表查找,并在元表新增或修改变量值

lua 复制代码
local k = {name = "ming"}
local mt ={}
mt.__newindex = k

local t = {}
setmetatable(t,mt)
print(t.name) -- nil  查询
print(k.name) -- Y    查询

t.name = "YY" -- 到对应的k表 修改
print(k.name) -- YY   查询  
print(t.name) -- nil  查询

输出结果:

lua 复制代码
nil
ming
YY
nil
相关推荐
为何创造硅基生物7 小时前
C语言 结构体内存对齐规则(通俗易懂版)
c语言·开发语言
吃好睡好便好7 小时前
在Matlab中绘制横直方图
开发语言·学习·算法·matlab
星寂樱易李7 小时前
iperf3 + Python-- 网络带宽、网速、网络稳定性
开发语言·网络·python
仰泳之鹅8 小时前
【C语言】自定义数据类型2——联合体与枚举
c语言·开发语言·算法
之歆8 小时前
DAY_12JavaScript DOM 完全指南(二):实战与性能篇
开发语言·前端·javascript·ecmascript
cen__y9 小时前
Linux12(Git01)
linux·运维·服务器·c语言·开发语言·git
AI人工智能+电脑小能手9 小时前
【大白话说Java面试题 第65题】【JVM篇】第25题:谈谈对 OOM 的认识
java·开发语言·jvm
社交怪人10 小时前
【算平均分】信息学奥赛一本通C语言解法(题号2071)
c语言·开发语言
郭涤生10 小时前
不同主机之间网络通信-以太网连接复习
开发语言·rk3588
山居秋暝LS10 小时前
【无标题】RTX00安装paddle OCR,win11不能装最新的,也不能用GPU
开发语言·r语言