用继承的思想理解lua元表(转)
众所周知,lua最最核心的数据结构是table,是一个key-value hash表,可以用t.key或t[key]来查询。当key值不存在时,一般的hash表返回空值,但lua的table在一定条件下会触发元方法,在设置的元表table里继续查找,如果查到了,则返回元表里的值而不是空值。
跟继承类似:
A继承B,A:XXX(),如果A中没有此方法,则继续在B中查找
设置A的元表是B,A.key,如果A中没有key,在一定条件下到B中查找
1. lua查找元素的过程
local mt = {a = "mt"}
mt.__index = mt
local t = setmetatable({}, mt)
print("---------> ", t.a) ---> mt
t.a,在表t中查找"a",不存在,如果t设置了元表,并且元表设置了__index域,则在元表设置的__index域mt中继续查找,即返回mt。如果没有设置元表返回nil。如果元表没有设置__index域也返回nil。如果在mt没找到,继续在mt的元表中继续查找,以此类推
local mt1 = {a = "mt1"}
mt1.__index = mt1
local mt2 = setmetatable({}, mt1)
mt2.__index = mt2
local mt = setmetatable({}, mt2)
print(mt.a, mt2.a, mt1.a) ----> mt1 mt1 mt1
2. lua实现类
lua中并没有类的概念,但根据元表的特性很容易实现一个类。即设置obj表的元表为class表。有很多不同的实现思路,以下是一个常用的模板:
local class = {}
class.__index = class
function class.New(cls, name)
local self = setmetatable({}, cls)
self.name = name
return self
end
function class:print()
print("name = ", self.name)
end
local obj = class:New("abc")
obj:print() ---> name = abc
3.lua实现继承
利用元表的特性,设置子类的元表为父类,当在子类找不到时,在父类中继续查找。
local base = {}
base.__index = base
function base.New(cls, name)
local self = setmetatable({}, cls)
self.name = name
return self
end
function base:print()
print("name = ", self.name)
end
local class = setmetatable({}, base)
class.__index = class
function class.New(cls, name, age)
local self = base.New(cls, name)
self.age = age
return self
end
function class:print2()
self:print()
print("age = ", self.age)
end
local obj = class:New("abc", 10)
obj:print2() ---> name = abc age =10
4. lua的元表和元方法
lua的元表和元方法自定义一系列的操作集合,除了查找元素__index域外,还有__newindex, __gc, __tostring, __add等操作,详见http://cloudwu.github.io/lua53doc/manual.html
local mt = {
__tostring = function(t)
local s=""
for _, v in ipairs(t) do
s = s .. v .. ","
end
return s
end,
__add = function(t1, t2)
local t = {}
for i, v in ipairs(t1) do
t[i] = v
end
for i, v in ipairs(t2) do
t[i] = (t[i] or 0) + v
end
return t
end,
}
local t = setmetatable({1,2,3,4,5}, mt)
print(t) ---> 1,2,3,4,5
local t1 = setmetatable({1,2,3}, mt)
local t2 = setmetatable({10,20,30,40,50}, mt)
local t3 = setmetatable(t1+t2, mt)
print(t3) ---> 11,22,33,40,50
注:如果用rawget(t, key),rawset(t, key, value),是不会触发元方法的,只在t中操作

浙公网安备 33010602011771号