天天看点

Lua的默认metamethod列表

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回收前的调用,相当于析构。如果没有则直接回收了

继续阅读