1.元表其实也是lua中的一种表,即table,
但是它可以自定义某个表的行为,比如运算符重载、默认值查找、访问控制等
2.当一个表 t 进行某些操作(如 t1 + t2、访问 t.key)时,
Lua 会检查 t 是否有元表,并尝试调用元表中的元方法
local mt = {}
--[[
__newindex 元方法是当table发生赋值的时候被调用
]]--
mt.__newindex = function()
assert(false, "attempt change const value")
end
--[[
这里将mt设置为是a的元表,可以看出mt也是一个普通的table,
但是mt中对元方法__newindex 进行了重写,此时就改变了a表的一些行为
]]--
local a = {}
setmetatable(a, mt)
--[[
对表a进行赋值,发现表a存在着元表mt,且mt中重写了__newindex元方法,此时触发assert
]]--
a[2] = 10
当我们需要访问一个表中的某个元素的时候,会触发元表的__index方法
--默认值
local initval = {x = 99, y = 100}
local mt = {}
--[[
下面两个写法都可以
1.直接返回initval[下标]
2.是传入table和下标
]]
--mt.__index = initval
mt.__index = function(t, k)
print(t) --table: 000001AC80161E80
return initval[k]
end
local a = {x = 88}
print(a) --table: 000001AC80161E80
setmetatable(a, mt)
--[[
__index元方法是先从子类开始查找,它发现a中已经有了x这个下标,
然后直接返回。
当a中没有x这个下标的时候,会去查找他的元表中的__index方法。
]]
print(a.x) --88
print(a.y) --100
集合模块
local Set = {}
local mt = {}
--[[
当两个table 相加的时候 会触发元方法__add
__add调用Set模块的并集方法
]]
mt.__add = function(a, b) return Set.union(a, b) end
--创建一个set 并且设置元表是mt
Set.new = function(l)
local set = {}
setmetatable(set, mt);
for k, v in pairs(l) do
set[v] = true
end
return set
end
--两个集合的并集
Set.union = function (a, b)
local set = Set.new{}
for k, _ in pairs(a) do
set[k] = true
end
for k, _ in pairs(b) do
set[k] = true
end
return set
end
Set.toString = function(a)
local str = ""
for k, _ in pairs(a) do
str = str .. ", ".. k
end
return str
end
return Set
调用
local set1 = Set.new({1,2,3, 99})
local set2 = Set.new({2,3,4})
print(getmetatable(set1))
print(getmetatable(set2))
--两个table相加 求出并集
local set3 = set1 + set2
print(Set.toString(set3))
--上文那个只读表 可以通过这种方法来规避
rawset(a, 2, 10)
print(a[2]) --10
print(a.x) --88
print(a.y) --100
print(rawget(a, y)) --nil