在Lua中我们可以对table表进行赋值和获取,但是无法对两个table表进行操作,Lua中提供了元表可以对table表进行一些操作,并且提供了两个重要的方法:
方法 | 说明 |
---|---|
setmetatable(table,metatable) | 对指定的table表设置元表metatable |
getmetatable(table) | 获取table的元表 |
设置元表的方法比较简单:
local mytable = {}
local mymetatable = {}
setmetatable(mytable, mymetatable)
也可以简写成:
setmetatable({},{})
Lua中也可以对一些元方法进行重载,那么来看看都有那些元方法可以被重载。元方法中的__(是两个下划线)
元方法 | 说明 |
---|---|
__index | 查找table中索引值key,对table表的访问 |
__newindex | 对table表进行更新 |
__tostring | 输出字符串 |
__call | 调用值 |
__mode | 用于弱表 |
__metatable | 用于保护metatable不被访问 |
下面对以上元方法一一介绍。
当访问table时如果键没有值,则会访问table中的元表metatable中的__index,如果metatable是一个表,则会查找对应的键。
local testTable1 = {"a","b","c","d","e"}
local t = {hello = "value"}
setmetatable(t,{__index = testTable1})
print("testTable1:" , t[1])
print("t:" ,t.hello)
可以看出来第一个输出t[1]在 t 表中是不存在的,所以会访问testTable1表中的键。第二个在 t 表中可以找到则输出,所以输出结果为:
testTable1: a
t: value
对表进行更新,如果存在key则更新,若不存在则查找__newindex,若存在则赋值,不存在则新增。
local testTable1 = {"a","b","c","d","e"}
local t = {hello = "value"}
mytable = setmetatable(t,{__newindex = testTable1})
print("mytable:" ,mytable.hello)
mytable.aaa = "hello lua"
mytable[1] = "aaaaaaaaaaaaa"
print(mytable.aaa , testTable1.aaa)
print(mytable[1] , testTable1[1])
首先给t表设置元表,然后赋给一个新表mytable,先输出hello的键(注意这里用的是mytable而不是t),然后通过mytable表进行赋值,aaa不存在则调用__newindex元方法,也没有则新增,给[1]键进行赋值,然后输出,来看看输出结果。
mytable: value
nil hello lua
nil aaaaaaaaaaaaa
大家可以看到aaa不存在,会在testTable1表中进行新增,[1]已经存在则会进行赋值更新。
local testTable1 = {"a","b","c","d","e"}
testTable1 = setmetatable(testTable1 , {__tostring = function(self)
local result = ""
for i, v in ipairs(self) do
result = result .. "-" .. v
end
return result
end })
print(testTable1)
将table表的元素用“-”串起来,输出结果为:
-a-b-c-d-e
local table1 = {}
function func(self , args)
print("call func" , args)
end
setmetatable(table1 , {__call = func})
table1("Erick")
在示例中定义一个table表,然后定义一个方法用户输出一个字符串,然后采用setmatetable方法对table表进行调用原表设置,__call =方法的名称,然后可以使用table表名直接调用方法了,来看下输出结果。
call func Erick
local table1 = {}
key1 ={name = "hello"}
table1[key1] = 1
key1 = nil
key2 = {name = "key2"}
table1[key2] = 2
key2 = nil
---垃圾回收
collectgarbage()
for i, v in pairs(table1) do
print(i.name,v)
end
运行后发现还是可以输出,即使把key1和key2都置为nil了,说明没有被回收掉存在引用。
hello 1
key2 2
那么再来做下改动。
local table1 = {}
setmetatable(table1 , {__mode = "k"})
key1 ={name = "hello"}
table1[key1] = 1
key1 = nil
key2 = {name = "key2"}
table1[key2] = 2
key2 = nil
collectgarbage()
for i, v in pairs(table1) do
print(i.name,v)
end
仅仅增加一行setmatetable,最后输出发现什么都没有输出。
local table2 = {}
setmetatable(table2 , {__metatable = "you can`t access data"})
print(getmetatable(table2))
以上示例可以正常输出table2的对应原表结果为:
you can`t access data
但是如果对table2进行设置,则会报错。
local table2 = {}
setmetatable(table2 , {__metatable = "you can`t access data"})
print(getmetatable(table2))
setmetatable(table2,{})
在最后对table2进行设置,这时运行会报错。
G:\Lua\5.1\lua.exe: test.lua:22: cannot change a protected metatable
you can`t access data
stack traceback:
[C]: in function 'setmetatable'
test.lua:22: in main chunk
[C]: ?
以上是对元方法的介绍说明,那么再来看看还有那些操作是可以进行重载的。
来看看都有那些运算元方法
元方法 | 说明 |
---|---|
__add | 对应运算符“+” |
__sub | 对应运算符“-” |
__mul | 对应运算符“*” |
__div | 对应运算符“/” |
__mod | 对应运算符“%” |
__eq | 对应运算符“==” |
__lt | 对应运算符“<” |
__le | 对应运算符“<=” |
针对上述的__add元方法,举个示例
local table1 = {10,20,30,40}
local table2 = {50,60,70,80}
function sumtable(self,anothertable)
local setsum = {}
local result = {}
for i, v in pairs(self) do
setsum[v] =true
end
for i, v in pairs(anothertable) do
setsum[v] =true
end
for i, v in pairs(setsum) do
table.insert(result , i)
end
return result
end
setmetatable(table1 , {__add = sumtable})
local newtable = table1 + table2
for i, v in pairs(newtable) do
print(i,v)
end
将两个table的元素拼接起来,其他元方法大家自行验证吧。