柚子快报邀请码778899分享:lua元表详解

http://yzkb.51969.com/

https://www.cnblogs.com/blueberryzzz/p/8947446.html

 

 

元表的作用

元表是用来定义对table或userdata操作方式的表

举个例子

local t1 = {1}

local t2 = {2}

local t3 = t1 + t2

我们直接对两个table执行+运算,会报错

lua: /usercode/file.lua:3: attempt to perform arithmetic on local 't1' (a table value)

因为程序不知道如何对两个表执行+运行,这时候就需要通过元表来定义如何执行t1的+运算,有点类似于c语言中的运算符重载。

local mt = {}

--定义mt.__add元方法(其实就是元表中一个特殊的索引值)为将两个表的元素合并后返回一个新表

mt.__add = function(t1,t2)

local temp = {}

for _,v in pairs(t1) do

table.insert(temp,v)

end

for _,v in pairs(t2) do

table.insert(temp,v)

end

return temp

end

local t1 = {1,2,3}

local t2 = {2}

--设置t1的元表为mt

setmetatable(t1,mt)

local t3 = t1 + t2

--输出t3

local st = "{"

for _,v in pairs(t3) do

st = st..v..", "

end

st = st.."}"

print(st)

结果为:

{1, 2, 3, 2, }

因为程序在执行t1+t2的时候,会去调用t1的元表mt的__add元方法进行计算。具体的过程是:1.查看t1是否有元表,若有,则查看t1的元表是否有__add元方法,若有则调用。2.查看t2是否有元表,若有,则查看t2的元表是否有__add元方法,若有则调用。3.若都没有则会报错。所以说,我们通过定义了t1元表的__add元方法,达到了让两个表通过+号来相加的效果

元表的元方法

函数描述

__add

运算符 +

__sub

运算符 -

__mul

运算符 *

__ div

运算符 /

__mod

运算符 %

__unm

运算符 -(取反)

__concat

运算符 ..

__eq

运算符 ==

__lt

运算符 <

__le

运算符 <=

__call

当函数调用

__tostring

转化为字符串

__index

调用一个索引

__newindex

给一个索引赋值

由于那几个运算符使用类似,所以就不单独说明了,接下来说 __call, __tostring, __index, __newindex四个元方法。

__call

__call可以让table当做一个函数来使用。

local mt = {}

--__call的第一参数是表自己

mt.__call = function(mytable,...)

--输出所有参数

for _,v in ipairs{...} do

print(v)

end

end

t = {}

setmetatable(t,mt)

--将t当作一个函数调用

t(1,2,3)

结果:

1

2

3

__tostring

__tostring可以修改table转化为字符串的行为

local mt = {}

--参数是表自己

mt.__tostring = function(t)

local s = "{"

for i,v in ipairs(t) do

if i > 1 then

s = s..", "

end

s = s..v

end

s = s .."}"

return s

end

t = {1,2,3}

--直接输出t

print(t)

--将t的元表设为mt

setmetatable(t,mt)

--输出t

print(t)

结果:

table: 0x14e2050

{1, 2, 3}

__index

调用table的一个不存在的索引时,会使用到元表的__index元方法,和前几个元方法不同,__index可以是一个函数也可是一个table。作为函数:将表和索引作为参数传入__index元方法,return一个返回值

local mt = {}

--第一个参数是表自己,第二个参数是调用的索引

mt.__index = function(t,key)

return "it is "..key

end

t = {1,2,3}

--输出未定义的key索引,输出为nil

print(t.key)

setmetatable(t,mt)

--设置元表后输出未定义的key索引,调用元表的__index函数,返回"it is key"输出

print(t.key)

结果:

nil

it is key

作为table:查找__index元方法表,若有该索引,则返回该索引对应的值,否则返回nil

local mt = {}

mt.__index = {key = "it is key"}

t = {1,2,3}

--输出未定义的key索引,输出为nil

print(t.key)

setmetatable(t,mt)

--输出表中未定义,但元表的__index中定义的key索引时,输出__index中的key索引值"it is key"

print(t.key)

--输出表中未定义,但元表的__index中也未定义的值时,输出为nil

print(t.key2)

结果:

nil

it is key

nil

__newindex

当为table中一个不存在的索引赋值时,会去调用元表中的__newindex元方法作为函数__newindex是一个函数时会将赋值语句中的表、索引、赋的值当作参数去调用。不对表进行改变

local mt = {}

--第一个参数时表自己,第二个参数是索引,第三个参数是赋的值

mt.__newindex = function(t,index,value)

print("index is "..index)

print("value is "..value)

end

t = {key = "it is key"}

setmetatable(t,mt)

--输出表中已有索引key的值

print(t.key)

--为表中不存在的newKey索引赋值,调用了元表的__newIndex元方法,输出了参数信息

t.newKey = 10

--表中的newKey索引值还是空,上面看着是一个赋值操作,其实只是调用了__newIndex元方法,并没有对t中的元素进行改动

print(t.newKey)

结果:

it is key

index is newKey

value is 10

nil

作为table__newindex是一个table时,为t中不存在的索引赋值会将该索引和值赋到__newindex所指向的表中,不对原来的表进行改变。

local mt = {}

--将__newindex元方法设置为一个空表newTable

local newTable = {}

mt.__newindex = newTable

t = {}

setmetatable(t,mt)

print(t.newKey,newTable.newKey)

--对t中不存在的索引进行负值时,由于t的元表中的__newindex元方法指向了一个表,所以并没有对t中的索引进行赋值操作将,而是将__newindex所指向的newTable的newKey索引赋值为了"it is newKey"

t.newKey = "it is newKey"

print(t.newKey,newTable.newKey)

结果:

nil nil

nil it is newKey

rawget 和 rawset

有时候我们希望直接改动或获取表中的值时,就需要rawget和rawset方法了。rawget可以让你直接获取到表中索引的实际值,而不通过元表的__index元方法。

local mt = {}

mt.__index = {key = "it is key"}

t = {}

setmetatable(t,mt)

print(t.key)

--通过rawget直接获取t中的key索引

print(rawget(t,"key"))

结果:

it is key

nil

rawset可以让你直接为表中索引的赋值,而不通过元表的__newindex元方法。

local mt = {}

local newTable = {}

mt.__newindex = newTable

t = {}

setmetatable(t,mt)

print(t.newKey,newTable.newKey)

--通过rawset直接向t的newKey索引赋值

rawset(t,"newKey","it is newKey")

print(t.newKey,newTable.newKey)

结果:

nil nil

it is newKey nil

元表的使用场景

作为table的元表

通过为table设置元表可以在lua中实现面向对象编程。

作为userdata的元表

通过对userdata和元表可以实现在lua中对c中的结构进行面向对象式的访问。

柚子快报邀请码778899分享:lua元表详解

http://yzkb.51969.com/

好文链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。