Lua 元表(Metatable)
在 Lua table 中我们可以访问对应的key来得到value值,但是却无法对两个 table 进行操作。 因此 Lua
提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法。
例如,使用元表我们可以定义Lua如何计算两个table的相加操作a+b。
设置元表和返回元表
setmetatable(table,metatable): 对指定 table 设置元表(metatable),如果元表(metatable)中存在 __metatable 键值,setmetatable 会失败。
getmetatable(table): 返回对象的元表(metatable)。
例:
设置元表
mytable = {} -- 普通表
mymetatable = {} -- 元表
setmetatable(mytable,mymetatable) -- 把 mymetatable 设为 mytable 的元表
或者
mytable = setmetatable({},{})
返回对象元表
getmetatable(mytable) -- 返回mymetatable
元方法
__index 元方法
ps:这里有个坑,_index前面是两条下划线。
当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表,Lua会在表中查找相应的键。
例1:
> other = { foo = 3 }
> t = setmetatable({}, { __index = other })
> t.foo
3
> t.bar
nil
例2:
mytable = setmetatable({key1 = "value1"}, {
__index = function(mytable, key)
if key == "key2" then
return "metatablevalue"
else
return nil
end
end
})
print(mytable.key1,mytable.key2)
结果:
value1 metatablevalue
解释:
mytable 表赋值为 {key1 = “value1”};mytable 设置了元表,元方法为 __index;元方法 __index中设置key2=metatablevalue。
在mytable表中查找 key1,找到则返回该元素。
在mytable表中查找 key2,找不到该元素,继续查找元方法的 __index键值,返回_index函数。因为传入的是key2所以返回metatablevalue。
ps:即使将A的元表设置为B,而且B中也确实有这个成员,返回结果仍然会是nil,原因就是B的__index元方法没有赋值。
例子:
husband = {
car = 1
}
you = {
beautiful = 1
}
setmetatable(you, husband)
print(you.car)
结果为nil
husband = {
car = 1
}
husband.__index = husband--把husband的__index指向自己
you = {
beautiful = 1
}
setmetatable(you, husband)
print(you.car)
结果为1
__newindex 元方法
__newindex 元方法用来对表更新,__index则用来对表访问 。
当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果表存在这个索引则调用这个函数而不进行赋值操作。
mymetatable = {}
mytable =setmetatable({k1="v0"},{__newindex
例:
mymetatable = {}
mytable =setmetatable({k1="v0"},{__newindex = mymetatable})
print(mytable.k1)
mytable.newk="newv2"
print(mytable.newk,mymetatable.newk)
mytable.k1 = "newv1"
print(mytable.k1,mymetatable.k1)
结果:
v0
nil newv2
newv1 nil
[Finished in 0.1s]
执行mytable.newk="newv2"时,因为表中设置了元方法__newindex,而且是给表一个缺少的索引值newk,所以调用元方法而不进行赋值;执行mytable.k1 = "newv1"时,k1是已存在的,所以直接赋值。
rawset (table, index, value)
功能:设置表中指定索引的值,此函数不会调用任何元表的方法,此函数将返回table
例(更新表):
mytable = setmetatable({k1 = "v1"}, {
__newindex = function(mytable, key, value)
rawset(mytable, key, "\""..value.."\"")
end
})
mytable.k1 = "new v"
mytable.k2 = 4
print(mytable.k1,mytable.k2)
结果:
new v "4"
在上述代码中,_newindex指向一个自定义函数,其中将本应该新建给元表的索引新建给了mytable,是的没有table添加了新的索引k2,更新了mytable。
表操作符
insert(table,newkey,newvalue)
为表添加操作符,newkey后的(key,value)向后移动
__add
表相加
local j=3
mytable = setmetatable({ 1, 2, 3 }, {
__add = function(mytable, newtable)
for i = 1, 3 do
j=j+1
table.insert(mytable, j,newtable[i])
print(j)
end
return mytable
end
})
secondtable = {4,5,6}
mytable = mytable + secondtable
for k,v in ipairs(mytable) do
print(k,v)
end
键 | 符 |
---|---|
__add | 对应的运算符 ‘+’. |
__sub | 对应的运算符 ‘-’. |
__mul | 对应的运算符 ‘*’. |
__div | 对应的运算符 ‘/’. |
__mod | 对应的运算符 ‘%’. |
__unm | 对应的运算符 ‘-’. |
__concat | 对应的运算符 ‘…’. |
__eq | 对应的运算符 ‘==’. |
__lt | 对应的运算符 ‘<’. |
__le | 对应的运算符 ‘<=’. |
__call 元方法
用来计算{表元素之和+元表元素之和}
function t_maxn(t)--计算表长
local mn = 0
for k, v in pairs(t) do
if mn < k then
mn = k
end
end
return mn
end
mytable = setmetatable({67},{--定义元方法__call
__call = function(mytable,newtable)
sum=0
for i=1,t_maxn(mytable) do --计算表元素之和
sum = sum+mytable[i]
end
for j=1,t_maxn(newtable) do --表元素之和加上元表元素之和
sum=sum+newtable[j]
end
return sum
end
})
newtable = {13,40,64}
print(mytable(newtable))
结果:184
__tostring 元方法
用于修改表的输出行为
例(修改表的输出为和)
mytable = setmetatable({23,43,54,65},{
__tostring = function(mytable)
sum = 0
for k,v in pairs(mytable) do
sum =sum+v
end
return "表所有元素之和为:"..sum
end
})
print(mytable)
结果为:185
end~~