Lua基础之元表(metatable)

 

简介

Lua中的元表允许我们通过一个tableA特殊的键值自定义另一个tableB的行为,这些特殊的键值称为元方法,tableA则称为tableB的元表。

 

设置元表

  • setmetatable(table,metatable): 对指定 table 设置元表,如果元表中存在 __metatable 键值,setmetatable 会失败。
  • getmetatable(table): 返回对象的元表。

 

元方法

 

函数

描述

__index

调用一个索引

__newindex

给一个索引赋值

__add

运算符 +

__sub

运算符 -

__mul

运算符 *

__ div

运算符 /

__mod

运算符 %

__unm

运算符 -(取反)

__concat

运算符 ..

__eq

运算符 ==

__lt

运算符 <

__le

运算符 <=

__call

当函数调用

__tostring

转化为字符串

 

__index

__index用于对表访问。

当通过一个key来访问 tableA 的时候,如果这个key没有对应的value,即为nil,那么Lua就会寻找tableA的元表中的__index 键。

如果__index是一个tableB,Lua会在tableB查找相应的value,如果不存在则返回nil,存在则返回对应的value;

如果__index是一个函数,Lua就会调用那个函数,tableA和key会作为参数传递给函数。

tableA = {a = "valueA"}
tableB = {b = "valueB"}
setmetatable(tableA, {__index = tableB})

print(tableA.b)     -- 输出结果:valueB

setmetatable(tableA, {__index = function (t, k)
    print(t.a)      -- 输出结果:valueA
    return "return funcion"
end})

print(tableA.b)     -- 输出结果:return funcion

 

__newindex

__newindex 用于对表更新。

当给tableA一个不存在的key赋值时,Lua就会查找元表中的__newindex键。

如果__newindex是一个tableB,则该key和value赋值到tableB中,不对tabelA进行改变;

如果__newindex是一个函数,则将赋值语句中的tableA、key、value当作参数去调用该函数,不对tabelA进行改变。

tableA = {a = "valueA"}
tableB = {}

-- 如果__newindex是个table
setmetatable(tableA, {__newindex = tableB})

tableA.b = "valueB"

print(tableA.b)     -- 输出结果:nil
print(tableB.b)     -- 输出结果:valueB
tableA = {a = "valueA"}
tableB = {}


-- 如果__newindex是个function
setmetatable(tableA, {__newindex = function (t, k, v)
    print(t.a)      -- 输出结果:valueA
    print(k)        -- 输出结果:b
    print(v)        -- 输出结果:valueB
end})

tableA.b = "valueB"

print(tableA.b)     -- 输出结果:nil
print(tableB.b)     -- 输出结果:nil

 

__add

__add可以定义两个table之间的加法运算,类似于c语言中的运算符重载。具体步骤如下,

  1. 查看tableA是否有元表,若有,则查看tableA的元表是否有__add元方法,若有则以tableA和tableB作为参数调用;
  2. 查看tableB是否有元表,若有,则查看tableB的元表是否有__add元方法,若有则以tableA和tableB作为参数调用;
  3. 若tableA和tableB没有元表或__add则会报错。
tableA = {a = 1}
tableB = {b = 2}

setmetatable(tableA, {__add = function (t1, t2)
    return t1.a + t2.b
end})

print(tableA + tableB)     -- 输出结果:3

其余运算元方法的运用均类似于__add。

 

__call

__call可以将table封装成一个函数来调用,第一个参数是table本身,其余参数可以自定义。

table = {}

setmetatable(table, {__call = function (t, value)
    return value + 1
end})

print(table(3))     -- 输出结果:3
 

__tostring

__tostring可以自定义table的输出形式。

table = {}

setmetatable(table, {__tostring = function (t, value)
    return "I am a table."
end})

print(table)     -- 输出结果:I am a table.

 

rawget、rawset

若想直接改动或获取table中的value时,可以分别使用rawget和rawset。


rawget可以直接获取到表中索引的实际值,而不通过元表的__index元方法。

function rawget(table, key) end
tableA = {}
tableB = {b = "valueB"}

setmetatable(tableA, {__index = tableB})

print(tableA.b)             -- 输出结果:value

--通过rawget直接获取tableA中的b索引
print(rawget(tableA,"b"))   -- 输出结果:nil


rawset可以直接为table中索引的赋值,而不通过元表的__newindex元方法。

function rawset(table, key, value) end
tableA = {a = "valueA"}
tableB = {}

-- 如果__newindex是个table
setmetatable(tableA, {__newindex = tableB})

-- tableA.b = "valueB"           -- 会访问到__newindex
rawset(tableA, "b", "valueB")    -- 避开__newindex

print(tableA.b)     -- 输出结果:valueB
print(tableB.b)     -- 输出结果:nil

 

 

参考文献:

https://www.runoob.com/lua/lua-metatables.html

https://www.cnblogs.com/blueberryzzz/p/8947446.html

https://blog.csdn.net/xocoder/article/details/9028347

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值