当前位置: 首页 > news >正文

Lua中,表、元表、对象、类的解析

原文地址:Lua中,表、元表、对象、类的解析

欢迎参观我的网站:无敌牛 – 技术/著作/典籍/分享等

一、表(table)—— Lua 的唯一复合数据结构

1.1 本质

  • Lua 中唯一的内置复合数据结构
  • 可以同时作为:
    • 数组(array)
    • 字典(map / hash / associative array)
    • 对象(object)
    • 模块(module)
    • 结构体(struct)
    • 命名空间(namespace)

1.2 基本语法

local t = {name = "Alice",           -- 字符串键age = 25,                 -- 字符串键,等价于 ["age"] = 25[true] = "yes",           -- 任意类型键(除 nil)[2] = "first",            -- 数字键,插入到第2个位置(索引从1开始),此位置向上至2位置的原有数据,移动到最末尾sayHello = function(self) -- 方法print("Hello, I'm " .. self.name)end
}

1.3 操作方式

t.name = "Bob"                -- 设置字段
print(t.age)                  -- 读取字段
t:sayHello()                  -- 调用方法(: 自动传 self)
t["sayHello"](t)              -- 等价写法for k, v in pairs(t) do       -- 遍历print(k, v)
end

1.4 表的核心作用

存储数据 + 行为(方法) → 成为“对象”的基础


二、元表(metatable)—— 表的“行为说明书”

2.1 本质

  • 元表本身也是一个表
  • 它包含“元方法(metamethods)”,用于定义“当对原表执行某些操作时,应该怎么做”

2.2 如何设置/获取

setmetatable(table, metatable)  -- 设置
getmetatable(table)             -- 获取

只有 table、userdata、thread 可以设元表(Lua 5.4+ 支持更多类型,但一般只用于 table)

2.3 常用元方法

元方法触发时机用途
__indext[key] 且 key 不存在默认值、继承、代理
__newindext[key] = value 且 key 不存在权限控制、日志、只读表
__adda + b自定义加法
__callf(...)让表像函数一样被调用
__tostringprint(t)tostring(t)自定义字符串表示
__len#t自定义长度
__eq, __lt, __le==, <, <=自定义比较

2.4 示例:__index 实现默认值

local defaults = { x = 0, y = 0, color = "white" }
local obj = {}
setmetatable(obj, { __index = defaults })print(obj.x)      -- 0 (从 defaults 获取)
obj.x = 10
print(obj.x)      -- 10 (现在 obj 自己有 x)

2.5 示例:__call 实现可调用对象

local counter = { count = 0 }
local mt = {__call = function(self, n)self.count = self.count + (n or 1)return self.countend
}
setmetatable(counter, mt)print(counter())     -- 1
print(counter(5))    -- 6

2.6 元表的核心作用

控制表的行为 —— 运算符重载、属性代理、函数调用、继承机制等


三、对象(object)—— 用表模拟的对象

3.1 什么是对象?

在 Lua 中,对象 = 表 + 方法 +(可选)元表

local obj = {x = 10,y = 20,move = function(self, dx, dy)self.x = self.x + dxself.y = self.y + dyend
}obj:move(5, 5)  -- : 语法糖,自动传 self
print(obj.x, obj.y)  -- 15  25

3.2 对象的核心特征

  • 状态(数据)x, y
  • 行为(方法)move
  • 标识(identity):每个表是独立对象

3.3 如何“构造”对象?

方式 1:直接字面量
local obj = { x = 10, y = 20 }
方式 2:工厂函数
local function newPoint(x, y)return {x = x or 0,y = y or 0,move = function(self, dx, dy)self.x = self.x + dxself.y = self.y + dyend}
endlocal p = newPoint(10, 20)
方式 3:用元表实现“类式”构造(见下文)

四、类(class)—— 用表 + 元表模拟的“类”

Lua 没有内置类,但可以用“原型继承”模拟:

4.1 基本“类”结构

-- “类”定义(其实是原型对象)
local Point = {}-- 定义 __tostring 行为(注意:这是给“实例”用的,不是给类本身)
local mt = {__tostring = function(self)return string.format("Point(%d, %d)", self.x, self.y)end
}-- 构造函数
function Point:new(x, y)local obj = {x = x or 0,y = y or 0}-- 关键:让实例(obj表)的元表要包含 __tostring 和 __indexsetmetatable(obj, {__index = self,      -- 初始化 __index 为 Point (继承Point的成员)。__tostring = mt.__tostring  -- 直接设置元方法})return obj
end-- 方法
function Point:move(dx, dy)self.x = self.x + dxself.y = self.y + dy
end-- 可选:让类本身(Point表)也支持 tostring(调试用)
setmetatable(Point, {__tostring = function()return "Class Point"end,__call = Point.new  -- 支持 Point(10, 20) 语法
})

4.2 使用“类”

-- 测试
local p1 = Point:new(10, 20)
print(p1)           -- Point(10, 20)
p1:move(5, 5)
print(p1)           -- Point(15, 25)local p2 = Point(30, 40)  -- 使用 __call
print(p2)           -- Point(30, 40)print(Point)        -- Class Point (可选功能)

4.3 继承怎么实现?

-- 子类
local ColorPoint = Point:new()  -- 创建子类原型
ColorPoint.color = "red"-- 设置 ColorPoint ,使用 __index 继承 Point
setmetatable(ColorPoint, { __index = Point })-- 定义 __instance_mt
ColorPoint.__instance_mt = {__index = function(self, key)-- 首先在 ColorPoint 中查找,把所有 父类 Point 的函数全部继承过来。local value = ColorPoint[key]if value ~= nil thenreturn valueend-- 如果没找到,再到 Point 中查找return Point[key]end,__tostring = function(self)return string.format("ColorPoint(%d, %d, %s)", self.x, self.y, self.color)end
}-- 子类构造函数
function ColorPoint:new(x, y, color)local obj = Point:new(x, y)  -- 调用父类构造函数obj.color = color or self.color-- 关键:重新设置元表为 ColorPoint 的实例元表setmetatable(obj, self.__instance_mt)return obj
end-- 可选:给 ColorPoint 类本身设置元表
setmetatable(ColorPoint, {__tostring = function() return "Class ColorPoint" end,__call = function(self, ...)return self:new(...)end  -- 修正:使用匿名函数调用 self:new(...)
})-- 子类测试
local cp = ColorPoint(50, 60, "blue")
print(cp)           -- ColorPoint(50, 60, blue) ← 终于正确了!
cp:move(10, 10)
print(cp)           -- ColorPoint(60, 70, blue) ← move 继承自 Point!print(ColorPoint)   -- Class ColorPoint

4.4 “类”的本质

一个“原型表” + 一个元表(用 __index 指向原型表)

  • 对象创建时,把自己的元表的 __index 指向“类”
  • 当访问对象不存在的字段时,Lua 会去“类”里找 → 实现“方法继承”

五、使用规则 & 最佳实践

5.1 表的使用规则

  • 用作数据容器、对象、模块
  • 避免混用数组和字典部分(除非必要)
  • 键尽量用字符串或数字(避免用布尔、函数、表作键,除非有特殊需求)
  • 使用 : 定义和调用方法,自动管理 self

5.2 元表的使用规则

  • 只用于定义行为,不用于存储业务数据
  • 多个对象可共享同一个元表(节省内存)
  • __index 最常用 —— 实现继承、默认值、代理
  • __newindex 用于拦截写操作 —— 实现只读表、日志、验证
  • __call 让对象/类可调用 —— 实现工厂、闭包
  • __tostring 用于调试和日志 —— 强烈推荐为对象实现

5.3 对象的使用规则

  • 状态(数据)存在对象自身
  • 方法存在“类”或原型中(通过 __index 继承)
  • 使用 obj:method() 而不是 obj.method(obj)
  • 避免在对象中存储函数(除非是闭包或动态生成),以节省内存

5.4 类的使用规则

  • “类”本身也是一个对象(原型)
  • 构造函数通常叫 newcreate
  • 使用 setmetatable(obj, { __index = self }) 实现继承
  • 方法定义在“类”上,对象通过 __index 继承
  • 支持多层继承(__index 链)
  • 可选:实现 __call 让类像函数一样被调用

5.5 性能注意事项

  • 频繁触发 __index/__newindex 有性能开销 → 避免在热路径使用
  • 共享元表 → 节省内存
  • 方法放在“类”中 → 避免每个对象复制函数

5.6 调试建议

  • 使用 getmetatable(obj) 查看对象的元表
  • 使用 debug.getmetatable(如果元表被保护)
  • 为对象实现 __tostring,方便 print 调试
  • 避免过度使用元表 —— 会让代码行为“不直观”

六、关系图谱总结

+----------------------+
|       元表           |
| (metatable)          |
| - __index → 类      | ← 定义“继承”行为
| - __call             | ← 定义“可调用”行为
| - __tostring         | ← 定义“打印”行为
+----------↑----------+|| setmetatable(obj, mt)|
+----------↓----------+
|        表            |
| (table)              |
| - x = 10             | ← 数据(状态)
| - y = 20             |
| - move = function    | ← 方法(行为)→ 通常放“类”里,通过 __index 继承
+----------↑----------+|| 是|
+----------↓----------+
|       对象           | ← 对象 = 表 + 元表
+----------↑----------+|| 从...创建|
+----------↓----------+
|        类            | ← 类 = 原型表 + 元表(通常 __index 指向自己)
| (其实是原型对象)     |
+----------------------+

七、一句话总结

在 Lua 中:

  • 是数据和方法的容器;
  • 元表 是表的行为控制器;
  • 对象 是一个表(带状态) + 可选元表(带行为);
  • 是一个特殊的表(原型) + 元表(用 __index 实现继承),用于创建和管理对象。
http://www.dtcms.com/a/486241.html

相关文章:

  • 在易语言里面做网站做二手物资哪个网站好
  • excel和word文件默认用office打开而不是用wps
  • 万网上传网站企业信用信息查询网官网
  • python学习之路(二)
  • IDEA弹框 Server‘s certificate is not trusted /服务器的证书不可信如何解决
  • ​rxn_yields 仓库介绍(https://rxn4chemistry.github.io/rxn_yields/)​
  • 前端视频课程添加水印,全屏不消失解决方法
  • 湖州网站建设哪家好google云平台 wordpress
  • Spring Boot性能优化详解
  • leetcode 329 矩阵中的最长递增路径
  • 生成模型实战 | 实时任意风格迁移
  • C++ --- 模版初阶
  • 外贸家具网站.net网站开发简介
  • Django 的文档接口
  • blender中对合并的物体重复设置材质,删除重复材质,批量复制材质
  • IDEA界面突然出现一条“竖线”,附解决办法
  • Git 学习及使用
  • 使用OpenGL加速图像处理
  • CUDA 调试器 sanitizer,检测数据竞争,竞争条件 race condition
  • Blender布料物理模拟生成插件 Simply Cloth Studio V1.4.4 + Simply Cloth Pro v3.0附使用教程
  • AWS CloudWatch:服务器的“眼睛”,实时监控一切动向
  • 云南省建设厅合同网站嵊州门户网站
  • 做网站需要学jsp我也来做外国网站购物
  • 异步数据采集实践:用 Python/Node.js 构建高并发淘宝商品 API 调用引擎
  • Spring Boot 3零基础教程,yml文件中配置和类的属性绑定,笔记15
  • Lua C API 中一段LUA建表过程解释
  • 用于大语言模型后训练阶段的新方法GVPO(Group Variance Policy Optimization)
  • k8s集群环境下Jenkins环境性能测试项目实战
  • 【k8s】在 k8s上部署一个 web 服务
  • 怎做网站网页设计属于什么行业