Lua中的元表Metatable
Metatable 元表
元表是table的一种特例 , 其用于定义对table或userdata操作方式 (如两个table的加法运算等).
例如 : 现需要对表tab1, tab2执行加法运算 (tab1 + tab2) . Lua将做出如下判断 :
- 查看
tab1是否有元表 , 若有则查看tab1的元表是否有__add元方法 , 若有则调用 . - 查看
tab2是否有元表 , 若有则查看tab2的元表是否有__add元方法 , 若有则调用 . - 若二者都没有对应的
__add元方法 , 则报错 .
因此 , 通过给table设置元表 , 并为其元定义__add元方法 , 即可实现该table的加法运算 .
设置元表 / 获取元表
setmetatable(table, metatable) - 设置元表
setmetatable(table, metatable) 设置 table 的元表为 metatable , 并返回 table .
- 若元表中存在
__metatable键值 , 则函数setmetatable失败 .
getmetatable(object) - 获取元表
getmetatable(object) 获取 object 的元表并返回 .
元表的元方法
上例中__add就是Lua中的一个原方法 , Lua中还有其他的原方法 , 可供实现并使用 .
常用元方法
| 元方法 | 描述 |
|---|---|
| __add | 运算符 + |
| __sub | 运算符 - |
| __mul | 运算符 * |
| __div | 运算符 / |
| __mod | 运算符 % |
| __unm | 运算符 - (取反) |
| __concat | 运算符 .. |
| __eq | 运算符 == |
| __it | 运算符 < |
| __le | 运算符 <= |
| __call | 当作函数调用 |
| __tostring | 转化为字符串 |
| __index | 调用一个索引 |
| __newindex | 给一个索引赋值 |
| __metatable | 用于设置访问元表的权限 |
__add元方法 与 其他运算符元方法
运算符元方法的使用方式都类似 , 以__add为例 :
__add 元方法使用示例 (Code/metatable/add.lua)
1 | local metaTab = {} -- 创建元表 |
输出

__call 元方法的使用
__call 可以让 table 当作一个函数来使用 .
注意 : __call 的第一个参数需要设置为表自身 .
_call示例 (Code/metatable/call.lua)
1 | local meteTab = {} -- 构造元表 |
输出

__tostring 元方法的使用
__tostring 元方法可以修改table , 将其转化为字符串(可以像字符串一样被print()输出) .
注意 : __tostring 的参数(唯一参数)为表自身
__tostring示例 (Code/metatable/tostring.lua)
1 | local metaTab = {} -- 构造元表 |
输出

__index 元方法的使用
当调用table的一个不存在的索引时 , 会使用到 __index 元方法 .
注意 : __index 可以是一个函数 , 也可以是一个table .
- 作为函数 : 将表和这个不存在的索引作为参数传入 , return 一个返回值 .
- 作为table : 调用不存在的索引时 , 将查找这个table , 若有该索引则返回对应的值 , 否则返回nil .
__index示例 (Code/metatable/index.lua)
1 | local metaTab = {} -- 构造元表 |
输出

__newindex 元方法的使用
为table中一个不存在的索引赋值时 , 将调用元表中的__newindex元方法 .
注意 : __newindex 与 __index 一样 , 可以作为一个function也可以作为一个table .
- 作为function : 将赋值语句中的
表,索引,值当作参数去调用 , 不对表进行改变 . - 作为table : 将该
索引和值赋到__newindex所指向的表中 , 不对原有的表做出改变 .
__newindex示例 (Code/metatable/newindex.lua)
1 | local metaTab = {} -- 构造元表 |
输出

__metatable 的使用
__metatable 作为字符串出现 , 当一个表被设置为其他表的元表时 , 自动获得__metatable=nil .
一个拥有__metatable属性的表不可以被设置为其他表的元表 .
- 通过设置元表的
__metatable为一个字符串 , 可以禁止访问该元表中的成员或修改元表 . - 当出现这些操作时 , 自动返回该字符串 .
__metatable 示例 (Code/metatable/metatable.lua)
1 | local metaTable = {} -- 构造元表 |
输出

rawget(table, index) 与 rawset(table, index, value)
rawget(table, index)可以直接获取表table中索引index的实际值(nil) , 绕过__index.rawset(table, index, value)可以直接为表table中的索引index赋值(插入新元素) , 绕过__newindex.
元表的使用场景
- 作为table的元表 : 通过table设置元表 , 可以实现Lua中的面向对象编程
- 作为userdata的元表 : 通过对userdata设置元表 , 可以实现Lua对C结果进行面向对象式的访问 .