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}
相关推荐
猷咪20 分钟前
C++基础
开发语言·c++
IT·小灰灰22 分钟前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧23 分钟前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q24 分钟前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳024 分钟前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾24 分钟前
php 对接deepseek
android·开发语言·php
2601_9498683628 分钟前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
星火开发设计42 分钟前
类型别名 typedef:让复杂类型更简洁
开发语言·c++·学习·算法·函数·知识
qq_177767371 小时前
React Native鸿蒙跨平台数据使用监控应用技术,通过setInterval每5秒更新一次数据使用情况和套餐使用情况,模拟了真实应用中的数据监控场景
开发语言·前端·javascript·react native·react.js·ecmascript·harmonyos
一匹电信狗1 小时前
【LeetCode_21】合并两个有序链表
c语言·开发语言·数据结构·c++·算法·leetcode·stl