--[[
说明
1.以下使用的metamethod都是lua核心metamethod,使用的时候可以采用相应的操作符,如:__add可以解释成+。
2.metamethod需要放在metatable中使用
算术运算符对应的域:
__add(+), __sub(-), __mul(*), __div(/), __unm(-负), __pow(^幂)
关系运算符对应的域:
__eq(==), __lt(<), __le(<=)
无~=, >, >=, 可以通过上述关系运算符not操作来实现
其他:
字符串连接操作: __concat(..)
转化为字符串操作:__tostring,当使用函数print打印该变量时,首先利用该变量的__tostring函数进行字符串的转化
保护元表信息:__metatable
]]
Set = {}
Set.mt = {}
--[[
算术运算
]]
function Set.new(t)
local s = {}
setmetatable(s, Set.mt)
for _, item in ipairs(t) do
s[item] = true
end
return s
end
-- 求集合并集
function Set.union(s1, s2)
-- 两个集合的metatable必须相等,才能执行并集操作
if getmetatable(s1) ~= Set.mt or
getmetatable(s2) ~= Set.mt then
error("attempt to add a set with a non-set value", 2)
end
local res = Set.new({})
for item in pairs(s1) do
res[item] = true
end
for item in pairs(s2) do
res[item] = true
end
return res
end
-- 求集合交集
function Set.intersection(s1, s2)
if getmetatable(s1) ~= Set.mt or
getmetatable(s2) ~= Set.mt then
error("attempt to multify a set with a non-set value", 2)
end
local res = Set.new({})
for item in pairs(s1) do
res[item] = s2[item]
end
return res
end
-- 将集合转化为字符串
function Set.tostring(s)
local res = "{"
local sep = ""
for item in pairs(s) do
res = res .. sep .. item
sep = ", "
end
return res .. "}"
end
-- 打印集合
function Set.print(s)
print(Set.tostring(s))
end
Set.mt.__add = Set.union -- 设置+运算实现函数,集合并集
Set.mt.__mul = Set.intersection -- 设置*运算实现函数,集合交集
Set.mt.__tostring = Set.tostring
s1 = Set.new({1, 2, 3})
s2 = Set.new({3, 4, 5})
print(s1)
print(s2)
print(s1 + s2)
print(s1 * s2)
--[[
关系运算
]]
-- 小于等于
Set.mt.__le = function(s1, s2)
for item in pairs(s1) do
-- s1有的,s2中没有,则s2不包含s1
if not s2[item] then
return false
end
end
return true
end
-- 小于
Set.mt.__lt = function(s1, s2)
--[[
s1 <= s2,而且s1 ~= s2,
当s1 <= s2且s2 <= s1时,表示s1 == s2,所以这里增加一个判断条件是not(s2 <= s1) ]]
return s1 <= s2 and not(s2 <= s1)
end
-- 等于
Set.mt.__eq = function(s1, s2)
return s1 <= s2 and s2 <= s1
end
s3 = Set.new({1, 2, 3})
s4 = Set.new({1, 2, 3, 4})
print(s3 < s4)
print(s3 == s4)
print(s3 <= s4)
print(s3 == (s3 * s4))
s5 = {2, 3, 4}
print(3 == "a")
print(3 == s3) -- 相等比较,混合类型,则返回false,不会抛出异常
print(s5 == s3) -- 相等比较,相同类型,metadata不同,则返回false,不会抛出异常
--print(3 > s3) -- 非相等比较,混合类型,则直接抛出异常
--print(s5 > s3) -- 非相等比较,相同类型,metadata不同,则直接抛出异常
--[[
为元表设置属性__metatable,保护元表不会被读取,不会被修改
]]
Set.mt.__metatable = "none of your bussiness"
s6 = Set.new({})
print(getmetatable(s)) -- 获得元表,会直接返回上面设置的__metatable属性的值
setmetatable(s6, {}) -- 修改s6的元表,将会抛出异常