元表
有必要先说下元表,英文名:metatable。开始见到这个词,并不是很能理解元表的含义。于是查询meta-前缀的含义:一般科学技术领域,metaXXX意思为XXX of/about XXX。英文解释:is a prefix meaning “referring to itself.” 简单来说就是复合。放在lua语言中的metable:table about table。也就是说一个table的元表是为这个table服务的。原则上,lua中每一个值都可以有一个元表,只不过除了表以外的值赋予元表必须通过C代码或调试库完成(因为有风险)。每一个table都可以有一个元表,最多只能有一个。
元方法
元方法是和元表紧紧相连的产物。__index和__newindex就是两个比较常用的元方法
__index
local t = {}
print(t.name)
--> nil
上面的代码,毫无疑问,最后输出nil,因为t中并没有name的字段。
local mt = {
__index = {
name = "张三"
}
}
local t = {}
setmetatable(t, mt)--设置t的元表为mt
print(t.name)
--> 张三
为啥这次会输出张三?分析一下:首先去找t中的name字段,发现找不到,此时并没有停止操作,而是去t中的元表中__index字段中去寻找name字段,找到,输出。
简单来说,__index元方法的作用就是当引用一个不存在的字段时,会自动的去这个table的元表中的__index字段里去引用。__index可以是一个table,也可以是一个函数。看下面
local names = {
name = "张三"
}
local mt = {
__index = function(_, key) --key表示缺失的字段,_表示那张表,这里就是t
print("缺失的字段为:" .. key)
return names[key]
end
}
local t = {}
setmetatable(t, mt)--设置t的元表为mt
print(t.name)
--> 缺失的字段为:name
--> 张三
__newindex
简单来说,newindex就是用来捕捉并屏蔽赋值不存在的字段的操作。
通过以下例子来感受一下 捕捉和屏蔽两个功能
local mt = {
__newindex = function(_, key, value) --key表示缺失的字段,_表示那张表,这里就是t
print("捕捉到您正在给" .. key .. "赋值为:" .. value)
end
}
local t = {}
setmetatable(t, mt)--设置t的元表为mt
t.name = "ss"
print(t.name)
-->捕捉到您正在给name赋值为:ss
-->nil
分析一下:当想要赋值给t中不存在的字段name时,__newindex顺利捕捉到这个操作,并且把该赋值操作屏蔽,最后该字段还是为nil。
尝试用__index和__newindex写一张只读表
试想一下你是一个主程,不希望手下的新人修改你的代码,那么你就可以写一张只读表。
function ReadOnly(t)
local mt = {
__index = t,
__newindex = function(t, k, v)
print("捕捉到您正在给" .. k.. "赋值为:" .. v)
end
}
local proxy = {}
setmattable(proxy, mt)
return proxy
end
names = ReadOnly({name1 = "张三", name2 = "李四", name3 = "王五"})
print(names.name1)
names.name2 = "赵六"
-->张三
-->捕捉到您正在给name2 赋值为:赵六
分析一下,proxy就是一个代理,当赋值names中的name2字段时,实际上是赋值它的代理proxy中的name2字段,proxy中当然不存在name2,于是就被proxy的元表中的__newindex捕捉并屏蔽。