初学者,有错误希望指正。
18————————————Metatables and Metamethods
--lua中不可以对两个表执行操作,也不能比较大小
--metatables 允许我们改变table的行为
--以相加为例,local a={} b={} a+b
--1 检查其中一个表是否带有metatale
--2 检查metatable是否有_add域
--3 如果有则调用_add函数
--[[
有趣的一点
任何一个表都可以是其他表的metatable,一组相关的表可以共享一个metatable(描述他们的共同行为)
一个表也可以是自身的metatable(描述其私自行为)
]]
--使用getmetatable()获取metatable,默认创建的表是一个不带metatable的表
t={}
print(getmetatble(t)) -->nil
--s使用setmetatable函数设置或者改变一个表的meteatable
t1={}
setmetatable(t,t1)
print(getmetatable(t)) --> t1
————————————————————————
#!/usr/local/bin/lua
Set={}
function Set.new(t)
local set={}
setmetatable(set,Set.mt)
--创建表的同时指定对应的metatable,这样使用set.new创建的所有集合都有相同的metatabla
for _,l in ipairs(t) do set[l]=true end
return set
end
function Set.union(a,b)
local res=Set.new{}
for k in pairs(a) do res[k]=true end
for k in pairs(b) do res[k]=true end
return res
end
function Set.intersection(a,b)
local res=Set.new{}
for k in pairs(a) do
res[k]=b[k]
end
return res
end
function Set.tostring(set)
local s="{"
local sep=""
for e in pairs(set) do
s=s..sep..e
sep=","
end
return s.."}"
end
function Set.print(s)
print(Set.tostring(s))
end
function list_print(s)
for k,v in pairs(s) do
print(k,v)
end
end
--定义一个普通的表作为metatale,避免污染命名空间,将其放在set内部
Set.mt={}
Set.mt.__add=Set.union
s1=Set.new{10,20,30,50}
s2=Set.new{30,34}
--print(getmetatable(s1))
--print(getmetatable(s2))
--给metatable增加__add函数
Set.mt.__add=Set.union
--[[
list_print(s1)
list_print(s2)
s3=s1+s2
list_print(s1)
list_print(s2)
list_print(s3)
print(type(s3))
Set.print(s3)
print(type(Set.tostring(s3)))
]]
Set.mt.__mul=Set.intersection
--可以通过设置不同的操作进行复杂操作,基础算术运算__add(加号),__mul(乘号),__sub(减号),__div(除号),__unm(负号)
--__pow(幂),这些只是表示符,真正代表操作的其实是=(等号)后的函数,并不一定就是与标识符名称一样的功能
--__concat : 定义连接行为
-- __ 这是双下划线,漏了话会报错attempt to perform arithmetic on a table value
Set,mt.__tostring=Set.tostring
--[[
库定义 的metamethods
metatable是一个普通的表,任何人都可以使用,可以在自己的metatables中定义自己的域
以tostring为例。print总是调用tostring来格式化输出
但是tostring会检查对象是否存在一个带有__tostring域调用自己定义的函数
输出
]]
Set.mt.__metatable="not your business"
print(getmetatable(s1))
setmetatable(s1,{})
--[[
setmetatable/getmetatable 函数也会使用metafield.在这种情况下,可以保护metatables,
通过对metatable设置了__metatable的值,getmetatale会返回这个值,setmetatable会出错
保护集合的同时也使使用者既不能看到也不能修改metatablee
输出
not your business
-/usr/local/bin/lua: ./metatable_test.lua:64: cannot change a protected metatable
]]
Set.print((s1+s2)*s1)
--[[
算术运算和关系运算的metamethods
————————————————————————————————————————————
以下摘自
http://manual.luaer.cn/2.8.html
"add": + 操作。
下面这个 getbinhandler 函数定义了 Lua 怎样选择一个处理器来作二元操作。 首先,Lua 尝试第一个操作数。 如果这个东西的类型没有定义这个操作的处理器,然后 Lua 会尝试第二个操作数。
function getbinhandler (op1, op2, event)
return metatable(op1)[event] or metatable(op2)[event]