Lua 元表(Metatable)
在 Lua table 中我们可以访问对应的
key来得到value值,但是却无法对两个table进行操作(比如相加)。 因此 Lua 提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法。 例如,使用元表我们可以定义 Lua 如何计算两个table的相加操作a+b。 当 Lua 试图对两个表进行相加时,先检查两者之一是否有元表,之后检查是否有一个叫__add的字段,若找到,则调用对应的值。__add等字段,其对应的值(往往是一个函数或是table)就是"元方法"。 有两个很重要的函数来处理元表。
setmetatable(table,metatable)
对指定
table设置元表(metatable),如果元表(metatable)中存在__metatable键值,setmetatable会失败。
local table1 = { age = 12 }
local table2 = { name = '小明' }
table2.__metatable = '11'
setmetatable(table1, table2)
print(getmetatable(table1)) --11
getmetatable(table)
返回对象的元表
(metatable)。
__index 元方法
__index是:当我们访问一个表中的key不存在时,则会触发去寻找__index元方法,如果不存在,则返回nil,如果存在,则返回结果
table1 = { foo = 3 }
metaTable = {}
metaTable.__index = function()
return '__index是:当我们访问一个表中的`key`不存在时,则会触发去寻找__index元方法,如果不存在,则返回`nil`,如果存在,则返回结果'
end
setmetatable(table1, metaTable) -- 对指定 table1 设置元表(metatable)
print('table1.foo=', table1.foo) --foo存在,则调用table1.foo
print('table1.attribute=', table1.attribute)--attribute不存在,则会调用__index元方法
表元素查找规则
- 在表中查找,如果找到,返回该
key对应的值,找不到则继续 - 判断该表是否有元表,如果没有元表,返回
nil,有元表则继续。 - 判断元表有没有
__index方法,如果__index方法为nil,则返回nil,如果__index方法是一个表,则重复 1、2、3;
如果
__index方法是一个函数,Lua会以表和key为参数调用该函数,并返回该函数的返回值。如果我们希望在访问一个表时不调用
__index元方法,那么可以使用函数rawget,它在不考虑元表的情况下对表进行简单的访问,定义为:rawget (table, key)在不触发任何元方法的情况下 获取
table[key]的值。table必须是一张表;key可以是任何值。
local table1 = {}
local table2 = {}
local table3 = { aa = 10 }
table2.__index = table2
table3.__index = table3
setmetatable(table1, table2)
setmetatable(table2, table3)
print(table1.aa)
__newindex元方法
当对表中不存在的
key进行赋值时,如果这个表有__newindex元方法,则分两种情况:
__newindex指向table
local table1 = {bb=2}
local table2 = {}
setmetatable(table1, table2)
table2.__newindex = table2
table1.bb = 12
table2.aa = 10
print('table1.bb=', table1.bb)
print('table1.aa=', table1.aa)
print('table2.aa=', table2.aa)
对查询表赋值时候
key存在的则对查询表key进行赋值
查询表不存在
key则赋值给了__newindex指向的key进行赋值
__newindex指向函数
local table1 = { bb = 2 }
local table2 = {}
setmetatable(table1, table2)
table2.__newindex = function(table1, key, value)
print(table1, key, value)
end
table1.bb = 11
table1.aa = 11
print('table1.aa=', table1.aa)
print('table1.bb=', table1.bb)
给表创建新
key时会调用这个函数
rawset (table, key, value)为原始表赋值
如果我们想为原始表进行赋值,可以使用rawset方法
rawset (table, key, value)
在不触发任何元方法的情况下将table[key]值设为value。table必须是一张表,key可以是nil与NaN之外的任何值。value可以是任何Lua值。
rawset(table1,"aa",456)
print(table1.aa) -- 456