原文地址http://www.daileinote.com/computer/lua/13
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
--]]
总结
1.本文只是对lua元表做简单的介绍,如果有疑问可以给我留言
2.lua的版本为5.1,运行环境centos7 64位
3.原文地址http://www.daileinote.com/computer/lua/13