0、手册应该是学习语言的最好的文档,一边看文档,一边想把它记录下来,lua 5.2 英文手册地址:http://www.lua.org/manual/5.2/manual.html
在lua中,任何值都可以拥有元表(metatable)。元表本质是就是lua中table,但同时通过元表可以自定义在某些值上的操作。通过设置元表中特定的域(fields)值,可以改变某些值的操作行为。比如,当非数值类型的值执行加法运算时,lua就会检测该值的元表是否存在"__add"域。如果能找到,lua就会调用该函数,执行加法运算。
metatable(obj)[event]
该表达式等同于
rawget(getmetatable(obj) or {},event)
这说明了访问某个对象的元方法,不会调用其他的元方法,并且访问一个没有元表的对象也不会fail,只是简单的返回nil。
function getbinhandler(op1,op2,event)
return metatable(op1)[event] or metatable(op2)[event]
end
function add_event(op1,op2)
local o1,o2 = tonumber(op1),tonubmer(op2)
if o1 and o2 then --都是数值类型
return o1 + o2
esle
lcoal h = getbinhandler(op1,op2,"__add")
if h then
return(h(op1,op2))
else
error(...)
end
end
end
function unm_event(op)
local o = tonumber(op)
if o then --如果是数值类型
return -o --直接有默认的操作返货
else
local h = metatable(op).__unm
if h then
return (h(op))
else
error(···)
end
end
end
"concat": .. 操作:
function concat_evnet(op1,op2)
if (type(op1) == "string" or type(op1) == "number") and
(type(op2) == "string" or type(op2) == "number") then
return op1 .. op2
else
local h = getbinhandler(op1,op2,"__concat")
if h then
return (h(op1,op2))
else
error(...)
end
end
end
"len": #操作
function len_evnet(op)
if type(op) == "string" then
return strlen(op)
else
local h = metatable(op).__len
if h then
return (h(op))
elseif type(op) == "table" then
return #op
else
error(...)
end
end
end
"eq":==操作,下面的getequalhandler函数展示了equality操作是怎么选择元方法的。只有当两个值的具有相同的类型和相同的元方法,才认为存在这样的元方法,并且只针对table和userdata类型。
function getequalhandler(op1,op2)
if type(op1) ~= type(op2) or
(type(op1) ~= "table" and type(op2) ~= "userdata") then
return nil
end
local mm1 = metatable(op1).__eq
local mm2 = metatable(op2).__eq
if mm1 == mm2 then
return mm1
else
return nil
end
en
"eq"evnt定义如下:
function eq_event(op1,op2)
if op1 == op2 then
return true
end
local h = getequalhandler(op1,op2)
if h then
return not not h(op1,op2) --这样做,一定会要么返回true或false,确保返回结果一定是boolean类型
else
return false
end
end
"lt":<操作
function lt_event(op1,op2)
if type(op1) == "number" and type(op2) == "number" then
return op1 < op2
elseif type(op1) == "string" and type(op2) == "string" then
return op1 < op2
else
local h = getbinhandler(op1,op2,"__lt")
if h then
return not not h(op1,op2) --保证返回结果为boolean型
esle
error(...)
end
end
end
"le": <=操作
function le_event(op1,op2)
if type(op1) == "number" and type(op2) == "number" then
return op1 <= op2
elseif type(op1) == "string" and type(op2) == "string" then
return op1 <= op2
else
local h = getbinhandler(op1,op2,"__le")
if h then
return not not h(op1,op2) --保证返回结果为boolean型
esle
h = getbinhandler(op1,op2,"__lt")
if h then
return not h(op2,op1)
else
error(...)
end
end
end
end
当不存在"le"的元方法时,lua会尝试使用"lt"的元方法,"a<=b"等价于"not (b < a)",同其他的比较操作运算一样,总是返回一个boolean类型。
function gettable_event(table,key)
local h
if type(table) == "table" then
local v = rawget(table,key)
if v ~= nil then
return v
end
h = metatable(table).__index
if h == nil then
return nil
end
else --不是table类型,始终调用元方法
h = metatable(table).__index
if h == nil then
error(...)
end
end
if type(h) == "function" then
return (h(table,key))
else
return h[key]
end
end
"newindex": table[key] = value,注意只有当访问table[key]不存在时,才会调用该元方法:
function settable_event(table,key,vale)
local h
if type(table) == "table" then
local v = rawget(table,key)
if v ~= nil then
rawset(table,key,vale)
return
end
h = metatable(table).__newindex
if h == nil then
rawset(table,key,vale)
return
end
else
h = metatable(table).__newindex
if h == nil then
error(...)
end
end
if type(h) == "function" then
h(table,key,value)
else
h[key] = value --注意这句,会重复这个操作
end
end
function function_event(func,...)
if type(func) == "function" then
return func(...)
else
local h = metatable(func).__call
if h then
return h(func,...)
else
error(...)
end
end
end