概念
元表其实很像面向对象中的继承,当给一张子表设置了一张元表时,该子表拥有元表的所有属性、方法。
任何表变量(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.name
end, -- 注意这里有个逗号
-- 第一个参数默认是子表
-- 后面的参数,就是在子表被当做函数调用的传递过来的参数
__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 = tab2
setmetatable(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.__newindex
print(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 true
end
}
setmetatable(tab1, tab3)
-- 比较两个表时,需要确保两个表的元素一致
print(tab1 == tab2)