Lua教程-元表

在Lua中我们可以对table表进行赋值和获取,但是无法对两个table表进行操作,Lua中提供了元表可以对table表进行一些操作,并且提供了两个重要的方法:

  • setmetatable(table,metatable)
  • getmetatable(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不被访问

下面对以上元方法一一介绍。

  • __index元方法

当访问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
  • __newindex元方法

对表进行更新,如果存在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]已经存在则会进行赋值更新。

  • __tostring元方法
    与java中的toString方法类似,可以输出字符串。
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
  • __call元方法
    调用方法
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
  • __mode元方法
    Lua是自动内存管理机制,通过垃圾回收期进行回收内存,如果这个元素被引用着,垃圾回收期是不知道是不是垃圾,因此需要一种与垃圾回收器协作的机制,那么就是弱引用,下来看一个示例
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,最后输出发现什么都没有输出。

  • __metatable元方法
    保护对象不能被看到也不能被修改,可以使用__metatable元方法,getmatetable则返回值,但是不能进行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的元素拼接起来,其他元方法大家自行验证吧。


Lua教程-元表_第1张图片

你可能感兴趣的:(Lua,Lua基础教程)