lua元表

lua元表其实就是为了扩展表格间的运算,比如之前我们如果让2个表格相加就会报错,一旦我们设置了元表并加上了__add属性,那么就会正常执行。

先看2个元表相关的函数

setmetatable(table,metatable)

将metatable设置为table的元表并返回table,如果metatable为nil,则删除table的元表。
如果table的元表里面存在__metatable则报错。


getmetatable(obj)

如果obj没有设置元表,返回nil,如果obj的元表里面有__metatable属性,则返回对应的值。
否则返回obj的元表

__metatable这个元表属性是用来起保护作用的,请看如下例子

local ta = {}

local tb = {__metatable = '沧浪水'}

--把tb设置成ta的元表并返回ta
setmetatable(ta,tb)
--注意由于tb中有__metatable属性,所以会保护ta的元表
--接下来对ta的元表做的所有修改操作都将报错
--试图读取ta的元表的直接返回__metatable对应的值

--试图删除ta的元表
--报错 cannot change a protected metatable
setmetatable(ta,nil)

-- 读取ta的元表
-- 直接返回 沧浪水
local res = getmetatable(ta)


__index元方法

比较常用,当我们通过键名去访问一个ta表格时,如果不存在这个键,lua还会尝试搜索ta的元表的__index,没有则返回nil
1.如果__index对应的是表格,直接搜索键名,搜索不到返回nil
2.如果__index所对应的是函数,则调用函数并传递ta和键名参数

例子

local ta = {}
ta['name_url'] = 'http://www.freecls.com'

--nil
print(ta.name)

local tb = {}
tb.__index = {name='沧浪水'}

setmetatable(ta,tb)

--沧浪水
print(ta.name)

--改成函数
tb.__index = function(ta,key)
    return ta[key..'_url']
end

--http://www.freecls.com
print(ta.name)


__newindex元方法

当对表格ta设置新值时,会查找ta的元表中是否有__newindex属性,如果存在,则ta赋值,把值赋给__newindex对应的表格

例子

local ta = {}
ta['name_url'] = 'http://www.freecls.com'

local tc = {}

local tb = {}
tb.__newindex = tc

setmetatable(ta,tb)

ta.name = '沧浪水'

print(ta.name)      --nil
print(tc.name)      --沧浪水


运算元方法

__add 对应的运算符 '+'
__sub 对应的运算符 '-'
__mul 对应的运算符 '*'
__div 对应的运算符 '/'
__mod 对应的运算符 '%'
__unm 对应的运算符 '-'
__concat 对应的运算符 '..'
__eq 对应的运算符 '=='
__lt 对应的运算符 '<'
__le 对应的运算符 '<='

在这里我只挑一个进行讲解,读者应该可以举一反三

假设我们想实现一个功能,就是2个表格用..操作时,把2个表格的内容合并返回

例子

local ta = {}
ta['url'] = 'http://www.freecls.com'

local tb = {}
tb.__concat = function(ta1,ta2)
    local ta = {}
    for k,v in pairs(ta1) do
        ta[k] = v
    end
    
    for k,v in pairs(ta2) do
        ta[k] = v
    end
    
    return ta
end

--设置元表
setmetatable(ta,tb)


local tc = {1,name='沧浪水',age='28',2}

--将会调用元方法__concat并传入ta,tc作为参数
local res = ta..tc

for k,v in pairs(res) do
    print(k,v)
end

--[[
1	1
2	2
url	http://www.freecls.com
name	沧浪水
age	28
--]]


__call元方法

设置了这个元方法,表格可以当做函数来使用

例子

local ta = setmetatable({'http://www.freecls.com'},{
    __call = function(ta1,str)
        print(#ta1)
        print('hello '..str)
    end
})

ta('freecls')

--[[
1
hello freecls
--]]


__tostring元方法

设置了这个元方法,可以改变表格的输出行为,默认的情况下会输出表格的内存地址

例子

local ta = {'hello', 'http://www.freecls.com'}

--table: 0x1943700
print(ta)

local ta = setmetatable(ta,{
    __tostring = function(ta)
        local str = ''
        for k,v in pairs(ta) do
            str = str..k..' '..v..'\n'
        end
        
        return str
    end
})

print(ta)

--[[
1 hello
2 http://www.freecls.com

--]]


上一篇: lua模块编写
下一篇: lua模拟面向对象编程
作者邮箱: 203328517@qq.com