元表metatable
metatable允许我们改变table的行为,每个行为关联了对应的元方法。
- setmetatable(table,metatable):对指定table 设置元表(metatable),如果元表中含有键__metatable , setmetatable则会失败。记得 返回值是table
- getmetatable(table):返回对象的元表(metatable)。
设置元表
mytable = {}
mymetatable = {}
setmetatable(mytable,mymetatable) -- 等同于mytable = setmetable({} , {})
getmetatable(mytable) -- 返回mymetatable,就是mytable的元表
元方法metamethod
__index metatable最常用的键,对表访问。
查找一个表元素的规则可以归纳为如下几个步骤:
- Step1:在表自身中查找,如果找到了就返回该元素,如果没找到则执行Step2
- Step2:判断该表是否有元表(操作指南),如果没有元表,则直接返回nil,如果有元表则继续执行Step3
- Step3:判断元表是否设置了有关索引失败的指南(__index元方法),如果没有(__index为nil),则直接返回nil;如果有__index方法是一张表,则重复执行Step1->Step2->Step3;如果__index方法是一个函数,则返回该函数的返回值
-- 继续承接上面的代码
mymetatable.__index={ foo = 3 } -- 设置元方法__index为table
print(mytable.foo)
-- 输出
-- 3
__index当做函数处理
mytable = { key1 = "C#" }
mymetatable = { __index = function(table,key)
if(key == "key2") then
return "Java"
else
return "Lua"
end
end}
setmetatable(mytable , mymetatable)
print(mytable.key1 , mytable.key2 , mytable.key3)
-- 输出
-- C# Java Lua
__newindex 用来对表更新(__index用来对表访问)。
当你给表的一个缺少的索引赋值,编译器就会查找__newindex元方法:如果存在则调用这个函数而不进行赋值操作。
mymetatable = {}
mytable = setmetatable({key1 = "value1"}, { __newindex = mymetatable })
print(mytable.key1)
mytable.newkey = "新值2"
print(mytable.newkey,mymetatable.newkey)
mytable.key1 = "新值1"
print(mytable.key1,mymetatable.key1)
-- 输出
-- value1
-- nil 新值2
-- 新值1 nil
以上实例中表设置了元方法 __newindex,在对新索引键(newkey)赋值时(mytable.newkey = “新值2”),会调用元方法,而不进行赋值。而如果对已存在的索引键(key1),则会进行赋值,而不调用元方法 __newindex。
__call 允许给table调用一个值时调用。
mytable = setmetatable({} , {
__call = function (mytable,key)
if(key == 1) then
print("111")
else
print("222")
end
end
})
mytable(1)
mytable(2)
-- 输出
-- 111
-- 222
当给mytable传入参数1时,这里会调用其元表中的__call元方法。元方法中定义的table就是代指普通表mytable,而key指的就是调用table时传入的参数,这里就是1。后面的逻辑就能搞懂了。
__tostring 用于修改表的输出行为。
mytable = setmetatable( {10 , 20 , 30 } , {
__tostring = function (table)
sum = 0
for _ , v in ipairs(table) do
sum = sum + v
end
return "表中所有元素之和"..sum
end
})
print(mytable)
-- 输出
-- 表中所有元素之和60
__add 对应的运算符 ‘+’
mytable={"Lua","Java","C","C#","C++"}--普通表
mymetatable={
--两表相加将新表中的元素添加到mytable中去
__add=function (tab,newtab)
local mi=0
for k,v in pairs(tab) do
if (k>mi)then
mi=k
end
end
for k,v in pairs(newtab) do
mi=mi+1
table.insert(tab,mi,v)
end
return tab
end
}--元表 元表扩展了普通表的行为
mytable=setmetatable(mytable,mymetatable)--给指定的表设定元表
newtab={"PHP","Phthon"}
--其中只要有一个表设置了元表都可以实现加法
v=mytable+newtab
for k,v in pairs(v) do
print(k,v)
end
-- 输出
--Lua
--Java
--C
--C#
--C++
--PHP
--Phthon
元方法 | 描述 |
---|---|
__sub | 对应的运算符 ‘-’ |
__mul | 对应的运算符 ‘*’ |
__div | 对应的运算符 ‘/’ |
__mod | 对应的运算符 ‘%’ |
__unm | 对应的运算符 ‘-’ |
__concat | 对应的运算符’…’ |
__eq | 对应的运算符’==’ |
__lt | 对应的运算符’<’ |
__le | 对应的运算符’<=’ |
__metatable | 保护元表 |
__concat(a, b) | 连接 |
__unm(a) | 相反数 |