Lua metatable & metamethod

示例代码

《programming in lua》里有一个案例很详细,就是写一个集合类的table,其负责筛选出table中不重复的元素并组合成一个新的table。本人按照自己的方式默写了一次,结果发现大差不差,代码如下:

Lua 复制代码
Set = {} --集合

--创建一个新集合
function Set.new(t)
    local set = {}
    for k,v in ipairs(t) do
        set[v] = true
    end
    return set
end

--集合并运算
function Set.union(a,b)
    local res = Set.new({})
    for k,v in pairs(a) do
        res[k] = true
    end
    for k,v in pairs(b) do
        res[k] = true
    end
    return res
end

--集合交运算
function Set.intersection(a,b)
    local res = Set.new({})
    for k,v in pairs(a) do
        if b[k] then
            res[k] = true
        end
    end
    return res
end

--集合转成字符串
function Set.tostring(set)
    local res = "{"
    local temp = ""
    for k,v in pairs(set) do
        res=res..temp..k
        temp = ","
    end
    res=res.."}"
    return res
end

local set = Set.new({1,3,4,5,6,3,4,5})
local set2 = Set.new({3,5,7})
local intersectSet = Set.intersection(set,set2)
local unionSet = Set.union(set,set2)
print(Set.tostring(intersectSet)) --{3,5}
print(Set.tostring(unionSet)) --{1,3,4,5,6,7}

算术运算metamethod

将上面每个函数都改写成metamethod的形式,相当于是运算符直接重载,而非显式调用函数名,可以达到同样的目的。赋值加法运算和乘法运算如下:

Lua 复制代码
setmetatable(Set,{
    __add = Set.union,
    __mul = Set.intersection,
})

--创建一个新集合
function Set.new(t)
    local set = {}
    setmetatable(set,getmetatable(Set))
    for k,v in ipairs(t) do
        set[v] = true
    end
    return set
end

关系运算metamethod

常见的关系运算即等于、小于、大于、大于等于、小于等于,只需要等于、小于、小于等于中的其中两个关系,即可推算出其他所有关系。如果是a大于b则是b小于等于a的运算;如果是a大于等于b则是b小于a的运算。在lua中给了三个关系运算metamethods:__eq(等于),__lt(小于),和__le(小于 等于)给关系运算符赋予特殊的含义。

于是为上面集合覆写关系运算:

Lua 复制代码
--小于等于
__le = function(a,b)
    for k,v in pairs(a) do
        if not b[k] then
            return false
        end
    end
    return true
end,
--等于
__eq = function(a,b)
    return a <= b and b <= a
end,
--小于
__lt = function(a,b)
    return a <= b and a ~= b
end

测试代码如下:

Lua 复制代码
local a = Set.new({1,3,4,5,6})
local b = Set.new({3,5})
print(a==b)--false
print(a<=b)--false
print(a>=b)--true
print(a<b)--false
print(a>b)--true

tostring

类似tostring函数也是有相应的metamethod供我们选择的,比如上方的tostring函数,可以设置metatable的元方法__tostring,这样的话就直接print(set)即可了:

Lua 复制代码
setmetatable(Set,{
    __add = Set.union,
    __mul = Set.intersection,
    __tostring = Set.tostring
})
print(intersectSet) --{3,5}
print(unionSet) --{1,3,4,5,6,7}
相关推荐
小成2023032026544 分钟前
C++~07补充
开发语言·c++
2401_885885044 小时前
国际语音C#接口怎么写?.NET环境下实现国际语音验证码批量下发
开发语言·c#·.net
程序猿乐锅4 小时前
【从0-1学习Python | 第七篇】Python 面向对象基础
开发语言·笔记·后端·python·学习·1024程序员节
Wang's Blog4 小时前
Java 项目实战: 交友项目 - 查询圈子个人动态:查询我的动态需求分析
java·开发语言·交友
凯瑟琳.奥古斯特4 小时前
力扣1016高效解法:剪枝优化技巧
开发语言·c++·算法·leetcode·职场和发展
坤坤子吖5 小时前
C++继承:友元、静态成员、多继承与组合
开发语言·c++·笔记·学习·1024程序员节
技术小甜甜5 小时前
【Cursor】Skill 被标黄色警告,怎么改成合格的 SKILL.md
开发语言·javascript·ai编程·cursor·1024程序员节·ai agent·skills
小小龙学IT6 小时前
Python Polars 高性能数据处理引擎深度解析
开发语言·python·rust·1024程序员节
quantdash_cc6 小时前
如何利用标的信息为研究股票池补充名称和交易所信息?
开发语言·python·pandas·量化交易·1024程序员节·股票数据·quantdash