Lua 本身没有 class 关键字,但通过元表(metatable)可以搭出完整的面向对象体系。核心只有一个机制:当你访问一个 table 不存在的键时,Lua 会去查它的 __index 元方法。把 __index 指向类模板,实例就能"继承"类上的所有方法——这就是 Lua 面向对象的全部秘密。
local Monster = {}
Monster.__index = Monster
function Monster.new(name, hp)
return setmetatable({ name = name, hp = hp }, Monster)
end
function Monster:hit(dmg)
self.hp = self.hp - dmg
if self.hp <= 0 then self:die() end
end
function Monster:die()
release_print(self.name .. " 被击杀")
end
Monster.new 里 setmetatable({实例字段}, Monster) 是点睛之笔:实例表只存自己的数据(name、hp),方法全部落在类表上,一百个实例共享同一份方法,内存开销极小。
子类把 __index 指向父类,就形成原型链:查找顺序是实例 → 子类 → 父类 → nil。子类重写 die 方法即实现多态,父类代码里调 self:die() 会自动派发到子类版本:
local Boss = setmetatable({}, { __index = Monster })
Boss.__index = Boss
function Boss.new(name)
local o = Monster.new(name, 10000)
return setmetatable(o, Boss)
end
function Boss:die() -- 重写
Monster.die(self) -- 可选:先走父类逻辑
release_print("掉落稀有装备")
end
第一,析构要自觉:Lua 没有自动析构,定义 Monster.delete(o) 做引用清理,销毁时必须显式调用,否则闭包和事件监听会泄漏。第二,类型判断用 getmetatable(o) == Monster,比给表塞个 type 字段更可靠。第三,热更友好性:方法都挂在类表上,热更时替换类表的方法即可全局生效,实例无需重建——这也是"实例只存数据"设计的另一个好处。第四,避免继承层级超过三层,Lua 的原型链查找是运行时的,层级越深排错越难,组合优于继承在这里同样成立。
把这套类系统封装成 class() 工具函数(自动处理 new/继承/super 引用),一个几百行的轻量 OOP 库就成型了,996 生态里大量框架正是这么做的。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
实战应用:用在哪里 祖玛教主倒下的瞬间,掉落的裁决之杖归谁?BOSS 的归属规则是打宝生态的宪法:单挑的归属清晰、组队的分配…
实战应用:用在哪里 新手村的前 30 分钟决定一款游戏的留存:玩家在这半小时里学会移动、战斗、拾取、加行会——学会的速度就是…
实战应用:用在哪里 每个功能都爱挂定时器:扫邮件的、刷怪的、发奖的、心跳的——一百个定时器各自为政,调度层的开销与定时器的数…
实战应用:用在哪里 丢弃裁决之杖、解散行会、删除好友——不可逆的操作一旦执行就没有后悔药。高危操作的确认设计是防误的闸门:让…
实战应用:用在哪里 前端的功能开发经常被服务器档在门外:后端的接口没写完,前端只能干等或造假数据。协议 Mock 在本地扮演…
实战应用:用在哪里 私聊是玩家社交的私信箱:交易的对口、好友的寒暄、行会的动员暗号全走私聊。私聊协议的要点是点对点的寻址、离…