王德发 发表于 2026-5-25 16:29:08

lua元表

这是 Lua 中最核心也最灵活的特性之一 —— 元表本质是给普通 table 附加 “自定义行为” 的特殊 table,比如让 table 支持加减运算、自定义索引查找规则等
[*]元表(Metatable):一个特殊的 table,用来定义另一个 table(被元表修饰的 table 称为 “原表”)的特殊行为;
[*]元方法(Metamethod):元表中以 __ 开头的键(比如 __add、__index),对应原表的自定义行为(比如 __add 定义加法运算);
[*]核心函数:
[*]setmetatable(t, mt):给 table t 设置元表 mt(返回 t);
[*]getmetatable(t):获取 table t 的元表(返回元表或 nil)。

__index(索引查找)当访问原表中不存在的键时,Lua 会去元表的 __index 中查找,这是 Lua 实现继承、默认值的核心。__index 可以是 table(优先查找该 table 的键),也可以是函数(自定义查找逻辑)。
Lua复制代码
-- 示例1:__index 为 table(继承的底层逻辑)local proto = {name = "默认名称", age = 18}-- 原型 tablelocal obj = {gender = "男"}                  -- 原表-- 给 obj 设置元表,__index 指向 protosetmetatable(obj, {__index = proto})-- 访问 obj 不存在的键,自动去 proto 找print(obj.name)-- 输出:默认名称(obj 无 name,从 proto 取)print(obj.age)   -- 输出:18(同理)print(obj.gender)-- 输出:男(obj 自身有,直接取)-- 示例2:__index 为函数(自定义查找逻辑)local t = {}setmetatable(t, {    __index = function(table, key)-- table=原表,key=访问的键      return "键 " .. key .. " 不存在,返回默认值"    end})print(t.abc)-- 输出:键 abc 不存在,返回默认值__newindex(索引赋值)当给原表中不存在的键赋值时,Lua 会调用元表的 __newindex,而非直接给原表添加键。
[*]用法和 __index 类似,可用于限制赋值、记录赋值日志、重定向赋值目标。

Lua复制代码
-- 示例:禁止给原表添加新键local t = {name = "张三"}setmetatable(t, {    __newindex = function(table, key, value)      print("赋值操作:表 =", table, "键 =", key, "值 =", value)      -- 使用 rawset 绕开元方法,直接给原表赋值(避免递归触发 __newindex)      rawset(table, key, value)    end})t.age = 20-- 报错:禁止给表添加新键:age(t 无 age 键,触发 __newindex)t.name = "李四"-- 正常执行(t 有 name 键,不触发 __newindex)__add/__sub/__mul 等通过元方法自定义原表的算术运算,比如让两个 table 支持加法。常用算术元方法:__add(+)、__sub(-)、__mul(*)、__div(/)、__eq(==)。
Lua复制代码
-- 示例:让 table 表示向量,支持加法运算local vec1 = {x = 1, y = 2}local vec2 = {x = 3, y = 4}-- 定义元表(包含 __add 元方法)local vec_mt = {    __add = function(a, b)-- a=左操作数,b=右操作数      return {x = a.x + b.x, y = a.y + b.y}    end}-- 给两个向量设置元表setmetatable(vec1, vec_mt)setmetatable(vec2, vec_mt)-- 向量加法(触发 __add)local vec3 = vec1 + vec2print(vec3.x, vec3.y)-- 输出:4 6__call(把 table 当作函数调用)当原表被当作函数调用时(比如 t()),触发 __call 元方法,可实现 “可调用的对象”。
Lua复制代码
local t = {name = "Lua"}setmetatable(t, {    __call = function(table, ...)-- table=原表,...=调用时的参数      print("调用了 table,参数:", ...)      print("table 的 name:", table.name)    end})-- 把 table 当作函数调用(触发 __call)t(10, 20)-- 输出:-- 调用了 table,参数:10 20-- table 的 name:Lua__tostring(自定义打印格式)当用 print() 打印原表时,触发 __tostring 元方法,替代默认的 table: 0xXXXXXXX 格式。
Lua复制代码
local person = {name = "张三", age = 20}setmetatable(person, {    __tostring = function(table)      return "Person: " .. table.name .. "(" .. table.age .. "岁)"    end})print(person)-- 输出:Person: 张三(20岁)(而非默认的内存地址)








页: [1]
查看完整版本: lua元表