setmetatable备忘
【作为metatable的对象才需要__index和__newindex,对象本身加上__index和__newindex没啥意义】
访问对象的成员, 如果成员不存在, 就会去metatable对象的__index上去找, 而不是直接去metatable对象上找
1 local a = {} 2 local mt = { str="123" } 3 setmetatable(a, mt) 4 5 print(a.str) --这边是nil, 因为不是在metatable对象本身上面找
下面的是对的
1 local a = {} 2 local mt = { str="123" } 3 mt.__index = mt --是在metatable的对象的__index上找 4 setmetatable(a, mt) 5 6 print(a.str) --这样就对了
也可以这样
local a = {} local mt = { str="123" } a.__index = mt setmetatable(a, a)
或者这样
1 local a = {} 2 3 local mt = { str="123" } 4 setmetatable(a, { __index = mt })
__newindex也是如此,设置对象的成员时, 如果成员不存在, 则到metatable对象的__newindex上去设置, 而不是直接在metatable对象上设置
1 local a = {} 2 3 local mt = { str="123" } 4 setmetatable(a, mt) 5 6 a.str = "456" 7 print(mt.str) --这边是123, 因为metatable的__newindex此时还是nil 8 9 mt.__newindex = mt 10 a.str = nil 11 a.str = "456" --成员不存在, 到metatable对象的__newindex上去设置 12 print(mt.str) --这边metable就被改掉了
【如果metatable对象没设置__index值,则就会拿到nil】
1 function Test1() 2 local obj = { a = 0 } 3 local objMeta = { b = 1 } 4 5 setmetatable(obj, objMeta) 6 7 print(obj.a) 8 print(obj.b) --obj对象没有b成员, 就会去metatable的__index上找, 但objMeta的__index值为nil, 所以得到的是nil 9 end 10 Test1()
【__index为函数时】
1 local obj = { a = 0 } 2 local objMeta = { b = 1 } 3 4 objMeta.__index = function(tb, key) 5 print("__index") 6 7 --return tb[key] --死循环爆栈 8 return rawget(tb, key) 9 end 10 11 print(obj.a) 12 print(obj.b) --是nil不是1, 因为rawget(tb, key)这边的tb还是obj
输出:
1
nil
【__tostring的值为函数, 不能是table】
【参考】