借鉴自:https://www.kancloud.cn/digest/luanote/119936
https://blog.csdn.net/xocoder/article/details/9028347
https://www.jb51.net/article/55155.htm
__index元方法(索引查询):
默认情况下,当我们访问一个table中不存在的字段时,得到的结果时nil,但是这种状况很容易被改变,lua是按照以下步骤决定是返回nil还是其他值的:
1.当访问一个table的字段时,如果table有这个字段,则直接访问对应的值
2.当table没有这个字段,判断该table是否有元表,如果没有元表,则返回nil有元表则继续
3.判断元表中有没有__index元方法,如果没有(即__index方法为nil),则返回nil,如果__index方法是一个table则重复1、2、3步骤,如果__index方法是一个函数,则这个字段作为该函数的第二个参数,然后返回该函数的返回值
__index元方法定义为函数时有2个参数:table本身,字段名 function(table,key)
Windows.mt.__index = function (table, key)中的table可以换成t、x等任意的变量,都表示为该表,如果此函数用不到该表,则可以写成Windows.mt.__index = function (_, key),也就是说如果__index赋值成一个元方法,则第一个参数则被默认赋值为该表,类比self的用法,__newindex同样使用
Windows = {}
Windows.default = {x = 0, y = 0, width = 100, height = 100, color = {r = 255, g = 255, b = 255}}
-- 创建元表
Windows.mt = {}
-- 声明构造函数
function Windows.new(o)
--将m设置为其元表
setmetatable(o, Windows.mt)
return o
end
-- 定义__index元方法
Windows.mt.__index = function (table, key)
return Windows.default[key]
end
local win = Windows.new({x = 10, y = 10})
print(win.x) -- >10 访问自身已经拥有的值
print(win.width) -- >100 访问default表中的值
print(win.color.r) -- >255 访问default表中的值
print(win.x)时,由于win变量本身就拥有x字段,所以就直接打印了其自身拥有的字段的值;print(win.width),由于win变量本身没有width字段,那么就去查找是否拥有元表,元表中是否有__index对应的元方法,由于存在__index元方法,返回了default表中的width字段的值,print(win.color.r)也是同样的道理
__newindex元方法(索引更新):
__newindex元方法与__index类似,__newindex用于更新table中的数据,而__index用于查询table中的数据。当对一个table中不存在的索引赋值时(存在索引当然就直接赋值了),在Lua中是按照以下步骤进行的:
1.判断该table是否有元表,如果有了元表,就查找元表中是否有__newindex元方法,如果没有元表,就直接添加这个索引,然后对应的赋值
2.如果有元表中__newindex方法,则去执行该方法,而不去执行赋值
3.如果该__newindex方法是一个table时,就在这个table中执行赋值,而不是原来的table,如果该__newindex方法是一个函数则执行该函数
__newindex元方法定义为函数时有3个参数:table本身、字段名、想要被赋予的值 function(table,key,value)