Lua元方法 · 花生肉泥

1.6k 词

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

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

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

1
2
3
4
5
6
local t = {}
print(getmetatable(t))

local t1 = {}
setmetatable(t,t1)
assert(getmetatable(t) == t1)

任何table都可以作为任何值的元表,而一组相关的table有可以共享一个通用的元表,此元表描述了他们共同行为,一个table甚至可以作为它自己的元表,用于描述其特有的行为,总之,任何搭配形式都是合法的。

在lua中,只能设置table元表,若要设置其他类型的元表,必须通过C代码完成,还存在一个特例,对于字符串,标准的字符串程序库为所有的字符串设置了一个元表,而其他类型在默认情况下都没有元表,例:

1
2
print(getmetatable("Hello World"))     -->table:0062EA18
print(getmetatable(10))

在table中,可以重新定义的元方法有以下几个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
__add(a,b)     -- 加法
__sub(a,b) -- 减法
__mul(a,b) -- 乘法
__div(a,b) -- 除法
__mod(a,b) -- 取模
__pow(a,b) -- 乘幂
__unm(a,b) -- 相反数
__concat(a,b) -- 连接
__len(a,b) -- 长度
__eq(a,b) -- 相等
__lt(a,b) -- 小于
__le(a,b) -- 小于等于
__index(a,b) -- 索引查询
__newindex(a,b,c) -- 索引更新
__call(a,...) -- 执行方法调用
__tostring(a) -- 字符串输出
__metatable -- 保护元表

算术类的元方法

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
34
35
36
37
38
39
Set = {}
local mt = {} -- 集合的元素

-- 根据参数列表中的值创建一个新集合
function (l)
local set = {}
setmetatable(set,mt)
for _,v in pairs(l) do
set[v] = true
end
return set
end
-- 并集操作
function Set.union(a, b)
local retSet = Set.new{} -- 此处相当于Set.new({})
for v in pairs(a) do retSet[v] = true end
for v in pairs(b) do retSet[v] = true end
return retSet
end

-- 交集操作
function Set.intersection(a, b)
local retSet = Set.new{}
for v in pairs(a) do retSet[v] = b[v] end
return retSet
end

-- 打印集合的操作
function Set.toString(set)
local tb = {}
for e in pairs(set) do
tb[#tb + 1] = e
end
return "{" .. table.concat(tb, ", ") .. "}"
end

function Set.print(s)
print(Set.toString(s))
end

现在,定义一个“+”来计算两个集合的并集,那么就需要让所有用于表示集合的table共享一个元表,并且在该元表中定义如何执行一个加法操作,首先创建一个常规的table