metamethod
"add": + 操作。
下面这个 getbinhandler 函数定义了 Lua 怎样选择一个处理器来作二元操作。 首先,Lua 尝试第一个操作数。 如果这个东西的类型没有定义这个操作的处理器,然后 Lua 会尝试第二个操作数。
function getbinhandler (op1, op2, event)
return metatable(op1)[event] or metatable(op2)[event]
end
通过这个函数, op1 + op2 的行为就是
function add_event (op1, op2)
local o1, o2 = tonumber(op1), tonumber(op2)
if o1 and o2 then -- 两个操作数都是数字?
return o1 + o2 -- 这里的 '+' 是原生的 'add'
else -- 至少一个操作数不是数字时
local h = getbinhandler(op1, op2, "__add")
if h then
-- 以两个操作数来调用处理器
return h(op1, op2)
else -- 没有处理器:缺省行为
error(···)
end
end
end
"sub": - 操作。 其行为类似于 "add" 操作。
"mul": * 操作。 其行为类似于 "add" 操作。
"div": / 操作。 其行为类似于 "add" 操作。
"mod": % 操作。 其行为类似于 "add" 操作, 它的原生操作是这样的 o1 - floor(o1/o2)*o2
"pow": ^ (幂)操作。 其行为类似于 "add" 操作, 它的原生操作是调用 pow 函数(通过 C math 库)。
"unm": 一元 - 操作。
function unm_event (op)
local o = tonumber(op)
if o then -- 操作数是数字?
return -o -- 这里的 '-' 是一个原生的 'unm'
else -- 操作数不是数字。
-- 尝试从操作数中得到处理器
local h = metatable(op).__unm
if h then
-- 以操作数为参数调用处理器
return h(op)
else -- 没有处理器:缺省行为
error(···)
end
end
end
"concat": .. (连接)操作,
function concat_event (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_event (op)
if type(op) == "string" then
return strlen(op) -- 原生的取字符串长度
elseif type(op) == "table" then
return #op -- 原生的取 table 长度
else
local h = metatable(op).__len
if h then
-- 调用操作数的处理器
return h(op)
else -- 没有处理器:缺省行为
error(···)
end
end
end
关于 table 的长度参见 §2.5.5 。
"eq": == 操作。 函数 getcomphandler 定义了 Lua 怎样选择一个处理器来作比较操作。 元方法仅仅在参于比较的两个对象类型相同且有对应操作相同的元方法时才起效。
function getcomphandler (op1, op2, event)
if type(op1) ~= type(op2) then return nil end
local mm1 = metatable(op1)[event]
local mm2 = metatable(op2)[event]
if mm1 == mm2 then return mm1 else return nil end
end
"eq" 事件按如下方式定义:
function eq_event (op1, op2)
if type(op1) ~= type(op2) then -- 不同的类型?
return false -- 不同的对象
end
if op1 == op2 then -- 原生的相等比较结果?
return true -- 对象相等
end
-- 尝试使用元方法
local h = getcomphandler(op1, op2, "__eq")
if h then
return h(op1, op2)
else
return false
end
end
a ~= b 等价于 not (a == b) 。
"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 = getcomphandler(op1, op2, "__lt")
if h then
return h(op1, op2)
else
error(···);
end
end
end
a > b 等价于 b < a.
"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 = getcomphandler(op1, op2, "__le")
if h then
return h(op1, op2)
else
h = getcomphandler(op1, op2, "__lt")
if h then
return not h(op2, op1)
else
error(···);
end
end
end
end
a >= b 等价于 b <= a 。 注意,如果元方法 "le" 没有提供,Lua 就尝试 "lt" , 它假定 a <= b 等价于 not (b < a) 。
"index": 取下标操作用于访问 table[key] 。
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
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 。
function settable_event (table, key, value)
local h
if type(table) == "table" then
local v = rawget(table, key)
if v ~= nil then rawset(table, key, value); return end
h = metatable(table).__newindex
if h == nil then rawset(table, key, value); return end
else
h = metatable(table).__newindex
if h == nil then
error(···);
end
end
if type(h) == "function" then
return h(table, key,value) -- 调用处理器
else h[key] = value -- 或是重复上述操作
end
end
"call": 当 Lua 调用一个值时调用。
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
__mode 域中是一个包含有字符 'k' 的字符串时, table 的键就是 weak 的。 如果 __mode 域中是一个包含有字符 'v' 的字符串时, table 的值就是 weak 的。
__tostring 获取对象的字符串描述
__gc 在gc回收前的调用,相当于析构。如果没有则直接回收了