Lua 元表(Metatable) __newindex之 一
__newindex 元方法用来对表更新,__index则用来对表访问 。
当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:
如果存在则调用这个函数而不进行赋值操作。
-- 表
bird = {}
bird.color = "red"
-- 上面说的缺少的索引是什么?
-- 表 bird 只有一个 color索引建
-- 现在要添加一个 wing
-- bird.wing = 2,此时 wing 就是bird 缺少的索引建
setmetatable(bird, {
__newindex = function(table, key, value)
print("----------------------")
for k, v in pairs(table) do
print(k.." "..v)
end
print("key:"..key.." value:"..value)
print("----------------------")
end
})
bird.color = "yellow"
print("bird.color:"..bird.color)
-- 输出:color yellow
-- bird.color 修改值成功
bird.wing = 2
-- 输出:
----------------------
color red
key:wing value:2
----------------------
print("bird.wing:"..tostring(bird.wing))
-- 输出:bird.wing:nil
为什么表bird 添加新索引 bird.wing = 2 调用到了匿名函数 function(table, key, value)
并且 bird.wing 最终结果是 nil,这是添加失败
因为添加元表调用 setmetatable 时,给 __newindex 赋值为匿名函数 function(table, key, value)
当添加新索引 bird.wing = 2 时,调用到了 __newindex,继而出发了匿名函数 **function(table, key, value)**函数内没有进行赋值操作,所以添加新索引键失败
那么如上将 __newindex 赋值为一个函数的意义何在?
如果想让一个表,不允许添加新索引键,只允许使用和修改现有的索引,
如上
bird.color = “yellow” ,已存在的索引建 color 的值可以读取和修改
bird.wing = 2,新添加的索引建 wing,则不允许添加
那么此时使用 __newindex 将能够达到目的
代码
-- 表
bird = {}
bird.color = "red"
animation = {}
animation.leg = 4
--(1)
animation.__newindex = animation
setmetatable(bird, animation)
--(2)
bird.wing = 2
print("bird.wing:"..tostring(bird.wing))
-- 输出:nil
print("animation.wing:"..tostring(animation.wing))
-- 输出:2
-- (3)
animation.__index = animation
bird.wing = 2
print("bird.wing:"..tostring(bird.wing))
-- 输出:2
print("animation.wing:"..tostring(animation.wing))
-- 输出:2
讲解上方代码
(1)部分
animation.__newindex = animation
表 animation 的元方法 __newindex 赋值给自己
将 bird 的元表设置为 animation
setmetatable(bird, animation)
(2) 部分
bird.wing = 2 表 bird 添加新索引键,先查找 bird 有没有 wing索引建,如果有则直接赋值,退出
如果没有wing 索引键,则开始调用元方法 __newindex 找到了表 animation,此时将 wing 索引键添加给表 animation
所以下方print 方法打印
print(“bird.wing:”…tostring(bird.wing))
bird.wing 为 nil
print(“animation.wing:”…tostring(animation.wing))
animation.wing 为 2
(3)部分
animation.__index = animation
将表 animation 的元方法__index 赋值给 animation
bird.wing = 2 逻辑同 (2) 部分
print(“bird.wing:”…tostring(bird.wing)) 此时,因为 wing 索引键被添加到表 animation,所以bird 想访问 wing时就会访问到 __index 继而向表 animation 中查找 wing 键,结果就能获取到了
代码
bird = {}
bird.color = "red"
animation = {}
animation.leg = 4
setmetatable(bird, {__newindex = animation})
bird.wing = 2
print("bird.wing:"..tostring(bird.wing))
-- 输出:nil
print("animation.wing:"..tostring(animation.wing))
-- 输出:2
print()
讲解上方代码
setmetatable(bird, {__newindex = animation})
设置元表,创建了一个新的匿名表 {__newindex = animation},并且将匿名表的 __newindex 赋值为 animation
当调用 bird.wing = 2 时,bird 查找自己没有 wing 索引键,
调用到匿名表的 __newindex,
继而找到 animation,
此时给 animation添加新索引键 wing 并且赋值为 2,
print(“bird.wing:”…tostring(bird.wing))
获取 bird.wing 的值,bird 没有索引键 wing
bird 无法通过 __index 访问到 animation,所以 bird.wing 为无效值
代码
bird = {}
bird.color = "red"
animation = {}
animation.leg = 4
local biology = {}
biology.__newindex = animation
setmetatable(bird, biology)
bird.wing = 2
print("bird.wing:"..tostring(bird.wing))
-- 输出:nil
print("biology.wing:"..tostring(biology.wing))
-- 输出:nil
print("animation.wing:"..tostring(animation.wing))
-- 输出:2
讲解上方代码
local biology = {}
biology.__newindex = animation
创建了一个新的表 biology 并且将表biology 的 __newindex 赋值为 animation
setmetatable(bird, biology)
赋值元表
bird.wing = 2 在 表 bird 中查找无法找到 wing 索引键,
继而访问 biology,表 biology 又从 __newindex 访问到 animation,
然后 animation 添加新索引键 wing 并赋值为 2
分别从三个表获取 wing 值如下
– bird.wing:nil
– biology.wing:nil
– animation.wing:2
代码
local bird = {}
bird.color = "red"
local animation = {}
animation.leg = 4
animation.__index = animation
local biology = {}
biology.breathe = true
biology.__index = biology
biology.__newindex = animation
-- 给 biology 赋值元表 为 animation
setmetatable(biology, animation)
-- 给 bird 赋值元表为 biology
setmetatable(bird, biology)
bird.wing = 2
print("bird.wing:"..tostring(bird.wing))
-- 输出:2
print("animation.wing:"..tostring(animation.wing))
-- 输出:2
print("biology.wing:"..tostring(biology.wing))
-- 输出:2
print()
bird.color = "yellow"
print("bird.color:"..tostring(bird.color))
-- 输出:bird.color:yellow
print("bird.breathe:"..tostring(bird.breathe))
-- 输出:bird.breathe:true
-- breathe 是从 biology 继承过来的
print("bird.leg:"..tostring(bird.leg))
-- 输出:bird.leg:4
-- leg 是从 animation 继承过来的
print("biology.leg:"..biology.leg)
-- 输出:biology.leg:4
-- leg 是从 animation 继承过来的
代码讲解
通过
animation.__index = animation
biology.__index = biology
biology.__newindex = animation
– 给 biology 赋值元表 为 animation
setmetatable(biology, animation)
– 给 bird 赋值元表为 biology
setmetatable(bird, biology)
将三个表串联起来,如果按照继承的关系就是
biology 继承
bird 继承 biology
bird 能获获取到 biology 和 animation 的索引键和函数
biology 能够获取到 animation 的索引键和函数