概念
元表其实很像面向对象中的继承,当给一张子表设置了一张元表时,该子表拥有元表的所有属性、方法。
任何表变量(table)都可以作为另一个表变量的元表。
任何表变量都可以有自己的元表(父表)。
当我们对子表或在子表中进行一些特殊的操作时,会执行元表中特定的内容。
操作
设置、获取元表
设置元表
setmetatable(table,metatable)
对指定 table 设置元表如果元表中存在 __metatable 键值,setmetatable 会失败。
tab1 = {} -- 子表tab2 = {} -- 元表(父表)-- 设置元表-- 参数一:子表-- 参数二:元表(父表)setmetatable(tab1, tab2)
获取元表
getmetatable(table): 返回对象的元表(metatable)。
tab1 = {} -- 子表tab2 = {} -- 元表(父表)-- 设置元表-- 参数一:子表-- 参数二:元表(父表)setmetatable(tab1, tab2)-- 获取元表tab3 = getmetatable(tab1)
特殊操作
__tostring() 方法
当子表被当做字符串使用,会触发元表中__toString()方法。
tab1 = {} -- 子表tab2 = {-- tostring方法,接收一个默认参数:子表__tostring = function (t1)return "I am oyyh."end}setmetatable(tab1, tab2)-- 把子表当做字符串使用,此时会执行tab2中的__toString()方法,并输出: I am oyyh.print(tab1)
__call() 方法
当子表被当做函数使用时,会触发元表中__call()方法。
-- 子表tab1 = {name = "table one"}-- 元表tab2 = {-- tostring方法,接收一个默认参数:子表__tostring = function (t)return t.nameend, -- 注意这里有个逗号-- 第一个参数默认是子表-- 后面的参数,就是在子表被当做函数调用的传递过来的参数__call = function (t1, var1)print(t1, var1)end}setmetatable(tab1, tab2)-- 把tab1当做函数调用,并传递一个参数进去tab1(123)-- 此时会输出table one 123
__index 属性
当子表找不到某个元素时,会去__index指定的表中查找
tab1 = {}tab2 = {age = 1,__index = {age = 2},-- __index = tab2 -- 不要这么写,这是一个坑,得到的会是个nil,如果要写,请在table外面写}-- 可以这么写-- tab2.__index = tab2setmetatable(tab1, tab2)print(tab1.age) -- 会输出2
__newindex 属性
当赋值时,如果赋值一个不存在的属性,那么会把这个值赋值到__newindex属性指向的表中,不会修改自己
-- 先不设置__newindex属性,看看效果tab1 = {}tab2 = {}setmetatable(tab1, tab2)tab1.age = 1 -- 此时会在tab1中添加age属性print(tab1.age) -- 输出1-- 使用__newindex属性tab2.__newindex = {}-- 下面name属性将会被添加到__newindex指向的表中tab1.name = "oyyh"print(tab1.name) -- 会输出nil,如果想输出值,可以设置 tab2.__index = tab2.__newindexprint(tab2.__newindex.name) -- 输出oyyh
运算符重载
当对子表进行运算符操作时,会触发元表中的指定方法:
- : __sub
- : __mul
- / : __div
- % : __mod
- ^ : __pow
- ..(拼接) : __concat
- == : __eq
- < : __lt
- <= : __le
条件运算符,没有!=, >, >=,只能通过not取反,实际上也不需要,因为 t1 > t2 等价于 t2 < t1
对两个table使用条件运算符时,两个表的元素必须一致
tab1 = {age = 1} -- 比较的第一个表tab2 = {age = 2} -- 比较的第二个表tab3 = {__eq = function (tab1, tab2)return trueend}setmetatable(tab1, tab3)-- 比较两个表时,需要确保两个表的元素一致print(tab1 == tab2)
