Lua元表

在Lua中,一个表可以通过key访问到对应的value,但是无法直接对两个表进行操作。因此,Lua提供了元表(metable),它允许改变表的行为,而每个行为都会有对应的元方法。

一、理解Lua元表

Lua中,元表的表现行为类似与C++中的操作符重载。比如,我们可以通过重载__add元方法,来计算两个Lua数组的并集,如下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
-- 定义两个集合
local set1 = {1,3,5,6}
local set2 = {2,4,6}

-- 定义一个用于重载__add元方法的函数。注意:函数的第一个参数是self
local union = function(self, another)
local set = {}
local result = {}

-- 借助表来保证集合的互异性
for k,v in pairs(self) do
set[v] = true
end

for k,v in pairs(another) do
set[v] = true
end

-- 加入结果集合
for k,v in pairs(set) do
table.insert(result,v)
end

return result
end

-- 重载set1的__add元方法
setmetatable(set1, { __add = union })

local set = set1 + set2
for _, v in pairs(set) do
print(v)
end

其运行结果为:

1
2
3
4
5
6
1
2
3
4
5
6

当我们对两个表进行相加操作时,Lua的执行流程如下:

  • 首先,检查两者之一是否有元表,

  • 然后,检查元表中是否有key为“__add”的元素,

  • 最后,调用key为“__add”的元素的值。

在这里,我们将key为“__add”的元素的值称为元方法。

二、设置元表

通过setmetatable函数,我们可以为一个表设置元表,如下示例:

1
2
3
4
5
local mt = {}
local t = {}

local res = setmetatable(t, mt)
print(type(res), res)

以上代码可以简写为:

1
2
local res = setmetatable({}, {})
print(type(res), res)

其执行结果为:

1
table	table: 0x564da1a6ef00

我们可以看到,setmetatable函数并不会直接修改原表,然是会返回一个新表

三、获取元表

通过getmetatable函数,我们可以获取到一个表的元表,如下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
local t = {1,2,3}
local res = getmetatable(t)
print(type(res), res)
print()

local mt = {2,4,6}
local t = {1,3,5}
local t = setmetatable(t, mt)
for k,v in pairs(t) do
print(k,v)
end
print()

for k,v in pairs(getmetatable(t)) do
print(k,v)
end

其执行结果为:

1
2
3
4
5
6
7
8
9
nil	nil

1 1
2 3
3 5

1 2
2 4
3 6

我们可以看到,一个表的元表并不能直接被访问到,需要借助getmetatable方法。


Lua元表
https://kuberxy.github.io/2020/12/20/Lua元表/
作者
Mr.x
发布于
2020年12月20日
许可协议