Lua —— 元表

144 阅读2分钟

一、概念

  • 任何表变量都可以作为另一个表变量的原表
  • 任何表变量都可以有自己的元表(父表)
  • 当子表进行一些特定操作时,会执行元表中的内容

二、设置原表

setmetable(子表,元表)

meta = {}
myTable = {}
setmetable(myTable,meta)

三、 特定操作: __tostring

当子表要被当作字符串使用时,会默认调用这个元表中的__tostring方法

meta = {
    __tostring = function()
        return "元表方法"
    end
}
mytable = {}
setmetable(myTable,meta)  --关联元表
print(mytable)  --把子表当字符串使用,调用元表tostring方法

输出:元表方法

当__tostring中有参数时,会默认把自己传进去

meta = {
    __tostring = function(t)
        return t.name  --需要已知表中有这个属性
    end
}
myTable = {
    name = "我是子表"
}
setmetable(myTable,meta)  --关联元表
print(mytable) 

输出:我是子表

四、 特定操作: __call

  • 当子被当作一个函数来使用时,会默认调用__call中的内容
  • 仅有当元表中实现了__call方法,子表才能被当作函数来使用
  • 当希望传参数时,默认第一个参数是调用者自己
meta = {
    __call = function(a,b)  --参数a是调用者(子表)自己,b才是是子表传的参数
        print(a,b) 
    end
}
myTable = {
    name = "我是子表"
}
setmetable(myTable,meta)  --关联元表
mytable("子表参数") 

输出:我是子表 子表参数

五、 特定操作: __index和__newIndex

  • __index:当子表中找不到某一个属性时,回到元表中__index指定的表去找属性,可以向上嵌套
meta = {
    name = "元表"
}
mytTable = {}
setmetable(myTable,meta)
print(myTable.name)

输出结果: nil
------------------------------------分割线-----------------------------------------
meta = {
    name = "元表"
}
--_ _indexd 的赋值建议卸载外部,避免出问题
meta.__index = meta  --元表的__index指向自己本身,可以指向其他表
mytTable = {}
setmetable(myTable,meta)
print(myTable.name)

输出结果: 元表
  • __newIndex:当赋值时,如果赋值一个不存在的索引,那么会把这个值赋值到newIndex所指的表中,不会修改自己(没有newIndex所指的表,那么在自己表中新增)
meta = {}
meta.__newIndex = {}
mytTable = {}
setmetable(myTable,meta)
mytTable.name = "子表"
print(myTable.name, myTable.__newIndex.name)

输出结果: nil 子表

六、 其他操作

  1. getmetatable(表) :获取元表
  2. rawget(表,属性) :会忽略元表__index指向的表,在自己身上找这个属性的值
    meta = { name = "元表"}
    meta.__index = meta
    mytTable = {}
    setmetable(myTable,meta)
    print(myTable.name)
    print(rawget(mytTable,"name"))
    
    输出结果: 元表 nil
    
  3. rawset(表,属性,值) :会忽略__newIndex指向的表,只给自己的表中属性赋值
    meta = {}
    meta.__newIndex = {}
    mytTable = {}
    setmetable(myTable,meta)
    mytTable.name = "子表"
    print(myTable.name, myTable.__newIndex.name)
    
    输出结果: 子表 nil