在 Lua table 中我们可以访问对应的key来得到value值,但是却无法对两个 table 进行操作。

因此 Lua 提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法。

例如,使用元表我们可以定义Lua如何计算两个table的相加操作a+b。

当Lua试图对两个表进行相加时,先检查两者之一是否有元表,之后检查是否有一个叫”add”的字段,若找到,则调用对应的值。”add”等即时字段,其对应的值(往往是一个函数或是table)就是”元方法”。

有两个很重要的函数来处理元表:

setmetatable(table,metatable):对指定table设置元表(metatable),如果元表(metatable)中存在__metatable键值,setmetatable会失败 。

getmetatable(table):返回对象的元表(metatable)。

__index 元方法

这是 metatable 最常用的键。

当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的index 键。如果index包含一个表格,Lua会在表格中查找相应的键。

Lua查找一个表元素时的规则,其实就是如下3个步骤:

1.在表中查找,如果找到,返回该元素,找不到则继续

2.判断该表是否有元表,如果没有元表,返回nil,有元表则继续。

3.判断元表有没有index方法,如果index方法为nil,则返回nil;如果index方法是一个表,则重复1、2、3;如果index方法是一个函数,则返回该函数的返回值。

__newindex 元方法

newindex 元方法用来对表更新,index则用来对表访问 。

当你给表的一个缺少的索引赋值,解释器就会查找__newindex 元方法:如果存在则调用这个函数而不进行赋值操作。

__call 元方法

__call 元方法在 Lua 调用一个值时调用。

__tostring 元方法

__tostring 元方法用于修改表的输出行为。

table存在两种行为:查询和修改(赋值),通过元方法index和newindex来改变table的这两种行为。

__index主要用于table的查询

table[key] 的访问过程,首先检查table表中是否存在key的字段,如果有则返回,否则检查是否有__index的元方法,没有返回nil,有则查找元方法。

__index元方法可以是一个函数,还可以是一个table。如果是一个函数,则以table和不存在的key作为参数方位该函数,

例如:__index = function(t,key)

如果是一个table时,就以相同的方式来访问这个table(即传入key访问元方法的table,如果存在则放回值,反之返回nil)

例如:__index = tab –此时会返回tab[key]的值

__index可以很好的实现具有默认值的table

function setDefaultValues(t,d)

​ local mt = {__index = function() return d end}

​ setmetatable(t, mt)

end

tab = {x=10,y=20}

print(tab.x ,tab.y,tab.z) --由于没有设置元方法则为nil

setDefaultValues(tab,100) --设置默认值(设置__index元方法)

print(tab.z) --检查到有__index的元方法则返回默认值

__newindex主要用于table的更新

当对table中不存在的索引赋值时,解释器就会查找__newindex元方法。如果有这个元方法,就调用这个元方法,而不是执行赋值。如果这个元方法是一个table,解释器就在table中进行赋值,而不是对原来的table。

local k = {}

local mt = {

​ __newindex = k

}

local t = {}

setmetatable(t, mt)

print("赋值前:")

for k,v in pairs(k) do

​ print(k ,v)

end

t[1] = 20

print("赋值后:t表中的值:")

for k,v in pairs(t) do

​ print(k ,v)

end

print("赋值后:k表中的值:")

for k,v in pairs(k) do

​ print(k ,v)

end