Lua元表——实现集合运算(一)

Lua元表(Metatable)
在 Lua table 中我们可以访问对应的key来得到value值,但是却无法对两个 table 进行操作。
因此 Lua 提供了元表(Metatable),允许我们改变table的行为,每个行为关联了对应的元方法。

举个例子:

local t1 = {1}
local t2 = {2}
local t3 = t1 + t2

就会报错:

lua: xx.lua:3: attempt to perform arithmetic on a table value (local 't1')

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

下面我们就一步步来介绍如何实现这样的集合运算。

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

元方法说明
__add(a, b)–加法
__sub(a, b)–减法
__mul(a, b)–乘法
__div(a, b)–除法
__mod(a, b)–取模
__pow(a, b)–乘幂
__unm(a)–相反数
__concat(a, b)–连接
__len(a)–长度
__eq(a, b)–相等
__lt(a, b)–小于
__le(a, b)–小于等于
__index(a, b)–索引查询
__newindex(a, b, c)–索引更新(PS:不懂的话,后面会有讲)
__call(a, …)–执行方法调用
__tostring(a)–字符串输出
__metatable–保护元表
__gc在 table 被回收时会触发的回调,可以用来做一些 lua内存泄露 及 资源释放等操作这个方法在 lua5.1 版本是不支持的,5.2以上的版本才可以直接使用。

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

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

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

t = {}
print(getmetatable(t))

输出nil

t = {}
t1 = {}
setmetatable(t, t1)
print(getmetatable(t) == t1)

输出true
说明:setmetatable(t, t1) 是将t1作为t的元表;getmetatable(t)是获取t的元表——即t1

我们仍然用自定义一个集合来来说明如何自定义元方法

1.创建一个集合

Set = {}
local mt = {}

function Set.new(l)
	local set = {}
	setmetatable(set, mt)
	for _, v in pairs(l) do
		set[v] = true
	end

	return set
end

2.打印集合

local s1 = Set.new{2, 4}
print(s1)

这个print会报错,原因是它会先找s1的元方法__tostring,如果没有这元方法就报错,而这个元方法是返回一个字符串,print调用就可以打印出来。

我们在上面的代码上添加

function Set.tostring(set)
	local tb = {}
	for k, _ in pairs(set) do
		tb[#tb + 1] = k
	end
	return "{" .. table.concat(tb, ", ") .. "}"
end

mt.__tostring = Set.tostring

这时候:

local s1 = Set.new{2, 4}
print(s1)

输出{2, 4}

3.输出集合的长度
我们需要先先实现__len元方法

--计算集合长度,即集合中元素的个数
function Set.len(set)
	local length = 0
	for k, _ in pairs(set) do
		length = length + 1
	end
	return length
end

mt.__len = Set.len
local s1 = Set.new{2, 4}
print(s1)
print(#s1)

输出
{2, 4}
2

全部代码:

Set = {}
local mt = {}

function Set.new(l)
	local set = {}
	setmetatable(set, mt)
	for _, v in pairs(l) do
		set[v] = true
	end

	return set
end

function Set.tostring(set)
	local tb = {}
	for k, _ in pairs(set) do
		tb[#tb + 1] = k
	end
	return "{" .. table.concat(tb, ", ") .. "}"
end

--计算集合长度,即集合中元素的个数
function Set.len(set)
	local length = 0
	for k, _ in pairs(set) do
		length = length + 1
	end
	return length
end

mt.__tostring = Set.tostring
mt.__len = Set.len

local s1 = Set.new{2, 4}
print(s1)
print(#s1)

接下来我们就继续实现这个集合的+,-,<= 等运算

参考:
Lua中的元表与元方法
lua元表详解
Lua 元表(Metatable)
lua5.1中实现__gc
Lua5.3中文帮助文档(云风翻译)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值