Metatable元表

lua中的每个值都可以用一个metatable

两个table类型的变量,你是无法直接用 + 操作的,如果你定义了一个指定的函数,就可以进行了

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

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

元表创建

lua在创建新的table时不会创建元表

1
2
local t = {1,2}
print(getmetatable(t))

使用getmetatable来获取一个table或userdata类型变量的元表,当创建新的table变量时,使用getmetatable去获得元表,将返回nil,同理,我们也可以使用setmetatable去设置一个table或者userdata类型变量的元表

lua代码中,只能设置table元表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
local t = {}
setmetatable(t,t1)
assert(getmetatable(t) == t1)

print(getmetatable("hello world"))
print(getmetatable(10))




=====结果=====
nil
table0061DE68
nil

__index元方法

当我们访问一个table中不存在的字段时,得到的结果是nil,但是这种状况很容易被改变,lua是按照以下步骤决定是返回nil还是其他的值:

当访问一个table字段时,如果table有这个字段,则直接返回对应值。

当table没有这个字段,则会促使解释器去查找一个叫__index的元方法,接下来就会调用对应的元方法,返回元方法的值。

如果没有这个元方法,那么返回nil结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Windows = {}     -- 创建一个命名空间

-- 创建默认值表
Windows.default = {x=0,y=0,width=100,height=100,color={r=255,g=255,b=255}}

Windows.mt = {} -- 创建元表

-- 声明构造函数
function (o)
setmetatable(o,Windows.mt)
return 0
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
print(win.color.r) -- 255

__index元方法不必一定是一个函数,他还可以是一个table

__newindex元方法

newindex元方法与index类似,newindex用于更新table中的数据,而index用于查询table中的数据

lua解释器先判断这个table是否有元表

如果有元表,就查找元表中是否有__newindex元方法,如果没有元表,就直接添加这个索引,然后对应的赋值

如果有这个__newindex元方法,lua解释器就执行它,而不是执行赋值

如果这个__newindex对应的不是一个函数,而是一个table,lua解释器就在这个table中执行赋值么不是对原来的table

1
2
3
4
5
6
7
8
9
local tb1 = {}
local tb2 = {}
tb1.__newindex = tb2
tb2.__newindex = tb1

setmetatable(tb1,tb2)
setmetatable(tb2,tb1)

tb1.x = 10