Lua 元表(Metatable) __newindex之 一

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 = 2bird 添加新索引键,先查找 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 能获获取到 biologyanimation 的索引键和函数
biology 能够获取到 animation 的索引键和函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值