項目中有個公會對象,數據大部分存在data中,之前都是 u.data.point這樣訪問,太麻煩了。
于是通過設置__index 使之可以直接訪問屬性,u.point。
但是還是不能直接改屬性,u.point = 4,所以再設置了__newindex。
?
在設置了setmetatable之后,不能直接給u添加新屬性,因為設置了__newindex,新的屬性將直接加到u.data中的。
?
- Union?=?{??
- ????data?=?nil,??
- ????dirty?=?nil,??
- }??
- ---?生成新的對象??
- function?Union:new(o)??
- ????o?=?o?or?{}??
- ????setmetatable(o,self)??
- ????self.__index?=?self??
- ????return?o??
- end??
- ---?初始化Union數據??
- function?Union:init(data)??
- ????self:initTable()??
- ????self.data?=?data??
- ????local?meta?=?{}??
- ????meta.__index?=?function?(table,?key)??
- ????????if?Union[key]?~=?nil?then??
- ????????????return?Union[key]??
- ????????else??
- ????????????return?self.data[key]??
- ????????end??
- ????end??
- ????meta.__newindex?=?function(table,key,?value)??
- ????????self.data[key]?=?value??
- ????end??
- ????setmetatable(self,?meta)??
- end??
- function?Union:initTable()??
- ????if?self.data?==?nil?then??
- ????????self.data?=?{}??
- ????end??
- ????if?self.dirty?==?nil?then??
- ????????self.dirty?=?{}??
- ????end??
- end??
- function?Union:print()??
- ????print(self.point,?self.data.point)??
- end??
- function?pt()??
- ????print(data1.point,?data2.point,?u.point,?u.data.point)??
- end??
- u?=?Union:new()??
- data1?=?{point?=?3}??
- data2?=?{point?=?103}??
- u:init(data1)??
- pt()??
- u.point?=?4??
- pt()??
- u.data?=?data2??
- pt()??
- u.point?=?104??
- pt()??
?
?
?
通過修改__index和__newindex會獲得不同的結果。
?
1.正確結果
- function?Union:init(data)??
- ????self:initTable()??
- ????self.data?=?data??
- ????local?meta?=?{}??
- ????meta.__index?=?function?(table,?key)??
- ????????if?Union[key]?~=?nil?then??
- ????????????return?Union[key]??
- ????????else??
- ????????????return?self.data[key]??
- ????????end??
- ????end??
- ????meta.__newindex?=?function(table,key,?value)??
- ????????self.data[key]?=?value??
- ????end??
- ????setmetatable(self,?meta)??
- end??
3??? 103??? 3??? 3
4??? 103??? 4??? 4
4??? 103??? 103??? 103
4??? 104??? 104??? 104
?
2.錯誤的__newindex
- function?Union:init(data)??
- ????self:initTable()??
- ????self.data?=?data??
- ????local?meta?=?{}??
- ????meta.__index?=?function?(table,?key)??
- ????????if?Union[key]?~=?nil?then??
- ????????????return?Union[key]??
- ????????else??
- ????????????return?self.data[key]??
- ????????end??
- ????end??
- ????meta.__newindex?=?self.data??
- ????setmetatable(self,?meta)??
- end??
3??? 103??? 3??? 3
4??? 103??? 4??? 4
4??? 103??? 103??? 103
104??? 103??? 103??? 103
3.錯誤的__index
- function?Union:init(data)??
- ????self:initTable()??
- ????self.data?=?data??
- ????local?meta?=?{}??
- ????meta.__index?=?function?(table,?key)??
- ????????if?Union[key]?~=?nil?then??
- ????????????return?Union[key]??
- ????????else??
- ????????????return?data[key]??
- ????????end??
- ????end??
- ????meta.__newindex?=?function(table,key,?value)??
- ????????self.data[key]?=?value??
- ????end??
- ????setmetatable(self,?meta)??
- end??
3??? 103??? 3??? 3
4??? 103??? 4??? 4
4??? 103??? 4??? 103
4??? 104??? 4??? 104
?對象A在內部可以修改HP.外部對象只能訪問對象A的HP,不能修改.
這東西其實可以用__index和__newindex來實現.
__index指向對象A,這樣就可以訪問;
__newindex重寫,修改hp的話,就禁止.就可以完成他的需求.
下面給出簡單的代碼:
function cannotModifyHp(object) ???? local proxy = {} ???? local mt = { ???????? __index = object, ???? __newindex = function(t,k,v) ???????? if k ~= "hp" then ???????? object[k] = v ???????? end ???? end ???? } ???? setmetatable(proxy,mt) ???? return proxy end ? ?object = {hp = 10,age = 11} function object.sethp(self,newhp) ???? self.hp = newhp end ? ?o = cannotModifyHp(object) ? ?o.hp = 100 print(o.hp) ? ?o:sethp(111) print(o.hp) ? ?object:sethp(100) print(o.hp) |
function cannotModifyHp(object)
????
local proxy = {}
????
local mt = {
????????
__index = object,
????
__newindex = function(t,k,v)
????????
if
k ~=
"hp"
then
????????
object[k] = v
????????
end
????
end
????
}
????
setmetatable(proxy,mt)
????
return
proxy
end
object = {hp = 10,age = 11}
function object.sethp(self,newhp)
????
self.hp = newhp
end
?
?
o = cannotModifyHp(object)
?
?
o.hp = 100
print(o.hp)
?
?
o:sethp(111)
print(o.hp)
?
?
object:sethp(100)
print(o.hp)
?
這里影響程序的不同結果是upvalue導致的。
由于一般程序中有可能動態改data。所以建議用function設置__index和__newindex,尤其注意各個不同函數中self指向的是什么對象