lua元表详解
元表的作用
元表是用来定义对table或userdata操作方式的表
举个例子
1 | local t1 = {1} |
我们直接对两个table执行+运算,会报错
1 | lua: /usercode/file.lua:3: attempt to perform arithmetic on local 't1' (a table value) |
因为程序不知道如何对两个表执行+运行,这时候就需要通过元表来定义如何执行t1的+运算,有点类似于c语言中的运算符重载。
1 | local mt = {} |
结果为:
1 | {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当做一个函数来使用。
1 | local mt = {} |
结果:
1 | 1 |
__tostring
__tostring可以修改table转化为字符串的行为
1 | local mt = {} |
结果:
1 | table: 0x14e2050 |
__index
调用table的一个不存在的索引时,会使用到元表的__index元方法,和前几个元方法不同,__index可以是一个函数也可是一个table。
作为函数:
将表和索引作为参数传入__index元方法,return一个返回值
1 | local mt = {} |
结果:
1 | nil |
作为table:
查找__index元方法表,若有该索引,则返回该索引对应的值,否则返回nil
1 | local mt = {} |
结果:
1 | nil |
__newindex
当为table中一个不存在的索引赋值时,会去调用元表中的__newindex元方法
作为函数
__newindex是一个函数时会将赋值语句中的表、索引、赋的值当作参数去调用。不对表进行改变
1 | local mt = {} |
结果:
1 | it is key |
作为table
__newindex是一个table时,为t中不存在的索引赋值会将该索引和值赋到__newindex所指向的表中,不对原来的表进行改变。
1 | local mt = {} |
结果:
1 | nil nil |
rawget 和 rawset
有时候我们希望直接改动或获取表中的值时,就需要rawget和rawset方法了。
rawget可以让你直接获取到表中索引的实际值,而不通过元表的__index元方法。
1 | local mt = {} |
结果:
1 | it is key |
rawset可以让你直接为表中索引的赋值,而不通过元表的__newindex元方法。
1 | local mt = {} |
结果:
1 | nil nil |
元表的使用场景
作为table的元表
通过为table设置元表可以在lua中实现面向对象编程。
作为userdata的元表
通过对userdata和元表可以实现在lua中对c中的结构进行面向对象式的访问。