lua中对于metatable用法和原理的总结

<span style="font-family: Arial, Helvetica, sans-serif;">-- --metatable 可以作为继承的用法</span>
parent = {
  house = 1
}

parent.__index = parent    --如果没有这一句话  child即使是设置parent为元表  也不能找到parent中的内容. __index指向的内容是nil

child = {
  wife = 2
}

setmetatable(child, parent)
print(child.house)
print(child.wife)




parent.__newindex = function ( t, k ,v )
	-- t[k] = v
	if k == "house" then
		parent[k] = v * 2
	end
end
-- 等效于
-- parent.__newindex = parent 

child.house = 3
child.wife = 4

print(child.house)
print(child.wife)

parent.__index = nil 


child.house = 5
child.wife = 6

print(child.house)
print(child.wife)

--打印结果是:
-- 1
-- 2
-- 6
-- 4
-- nil
-- 6


2.metatable可以类似c++中重载操作符(重写元方法)   


f1 = { a = 1, b = 2 }
f2 = { a = 2 , b = 3 }

-- s = f1 + f2    现在的f1 和 f2 没有各自的__add函数
meta = {}

function meta.__add(f1, f2)
	local sum = {}
	sum.a = f1.a + f2.a 
	sum.b = f1.b + f2.b 
	return sum 
end

setmetatable(f1, meta)
setmetatable(f2, meta)

s = f1 + f2 
print(s.a)
print(s.b)

--需要重载的操作符
--算数类型
-- __add(a, b)                     for a + b
-- __sub(a, b)                     for a - b
-- __mul(a, b)                     for a * b
-- __div(a, b)                     for a / b
-- __mod(a, b)                     for a % b
-- __pow(a, b)                     for a ^ b
-- __unm(a)                        for -a
-- __concat(a, b)                  for a .. b
-- __len(a)                        for #a
--关系类型
-- __eq(a, b)                      for a == b
-- __lt(a, b)                      for a < b
-- __le(a, b)                      for a <= b
--table访问的元方法
-- __index(a, b)  <fn or a table>  for a.b
-- __newindex(a,b)
-- __newindex(a, b, c)             for a.b = c
-- __call(a, ...)                  for a(...)
-- 库定义的元方法
-- __metatable					    保护元表,不可读写
-- __tostring
3.metatable 可以当成一个类来使用
Parent = {}

function Parent:new()
	local newParent = { house = "white house" }
	self.__index = self 
	return setmetatable(newParent, self)
end

function Parent:Wife( )
	print("mother live in the "..self.house )
end

parent = Parent:new()
parent:Wife()


--通过类似类的方式来继承
Child = Parent:new()
function Child:Position()
	local ChildHouse = self.house
	print("child live in the "..ChildHouse)
	self:Wife()
end

child = Child:new()
child:Position()

-- lua中检查某值得顺序:比如child 的house 属性。  先到Child中去检查有没有某个字段。就会去检索__index这个元方法。
-- 即当需要访问一个字段在table中不存在的时候,解释器会去查找一个叫__index的元方法,如果没有该元方法,那么访问结果就是nil,不然就由这个元方法来提供最终结果。

test1 = { param1 = 1}
test2 = { param2 = 2}
test3 = { param3 = 3}

-- test2.__index = test1  等价于:
test2.__index = function(testTable , key)
	-- print(testTable)
	-- print(test3)
	-- print(key)
	-- print(test1[key])
	return test1[key]
end
setmetatable(test3 , test2)

print(test3.param1)
print(test3.param2)
print(test3.param3)

-- 这里的__index赋值就相当于  test2.__index = test1

--注释部分打印得出的结果是:
-- table: 0x7fe038c05440
-- table: 0x7fe038c05440
-- param1
-- 1
-- nil
-- table: 0x7fe038c05440
-- table: 0x7fe038c05440
-- param2
-- nil
-- nil
-- 3


--testTable的地址和test3的地址相同 ,由此可知,__index这种元方法会有一个默认形参是该表本身。而这里setmetatable只是给表设置了元表,真正查询字段的是根据元表中__index元方法所指向的表中的字段。而不是元表中的字段。

这里有个问题没有搞清楚,多打印出来一个nil这个nil是什么?  如果有理解的同学请在下面留言,指点我一下。

4.metatable的结合应用

--具有默认值的应用
function setDefault (mainTabel , returnValue)
	local mt = {__index = function () return returnValue end }
	setmetatable(mainTabel , mt)
end

tab = { x = 10 ,y = 20}
print(tab.x , tab.y , tab.z)
setDefault(tab, 0)
print(tab.x , tab.y , tab.z)


--只读属性的table
function readOnly (t)
	local proxy = {}
	local mt = { __index = t, __newindex = function (t, k ,v) print("it's a readOnly table ") end}
	setmetatable(proxy , mt)
	return proxy 
end

days = readOnly { 1 , 2 ,3 ,4 ,5 ,6 ,7}
print(days[1])

days[2] = 12
-- print(days[2])


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。