Lua 概览
自动关联目录:Lua 概览
一门语言值不值得投入,看的是它把复杂度放在哪里。Lua 的选择是:把复杂度交给使用者,换一个极小、极快、极易嵌入的内核。
设计取舍
| 取舍 | 换来什么 | 代价 |
|---|---|---|
| 只有 table 一种数据结构 | 内核极小,语义统一 | 数组/字典/对象靠约定区分 |
| 没有内建类系统 | 面向对象可以自由实现 | 每个项目一套写法 |
| 动态类型 + 解释执行 | 热更新、快速迭代 | 运行时开销与类型不安全 |
| 不提供多线程 | 无锁,实现简单 | 并发靠协程或多 VM |
| ANSI C 实现 | 到处都能编译嵌入 | 性能上限低于 JIT 语言 |
八种类型
| 类型 | 说明 |
|---|---|
nil | 空,全局变量默认值;也是"删除"的语义 |
boolean | 只有 nil 和 false 为假,0 和空串是真 |
number | 5.3 起区分 integer 与 float |
string | 不可变,带长度,内部有短字符串池 |
table | 唯一的数据结构,也是唯一的可变引用类型 |
function | 一等公民,可匿名、可闭包 |
userdata | 宿主(C)数据的载体,分轻量与完全两种 |
thread | 协程 |
只有 table、userdata、function、thread 是引用语义,其余都是值语义。判断相等:值类型比值,引用类型比地址。
Table
local t = {} -- 空表
t[1] = "a" -- 数组部分
t.name = "boss" -- 等价于 t["name"],哈希部分
print(#t) -- 1,# 只看数组部分的连续前缀元表(metatable)是 table 的"行为定制层":
| 元方法 | 触发时机 |
|---|---|
__index | 访问不存在的键(实现继承与默认值的关键) |
__newindex | 给不存在的键赋值(实现只读表、代理) |
__call | 把 table 当函数调用 |
__tostring / __len | print / # |
__add __eq __lt … | 运算符重载 |
__gc | 回收(只对 userdata 有效) |
函数与闭包
函数是词法作用域的:内层函数可以捕获外层局部变量,被捕获的变量叫 upvalue。
local function counter()
local n = 0
return function() n = n + 1 return n end
end闭包是 Lua 里实现"私有状态"的标准手段(比全局表干净得多)。注意 upvalue 是共享的:同一外层变量被多个闭包捕获时,它们看到的是同一个值。
协程
协程是协作式的:一次只有一个在跑,切换点显式,所以不需要锁。
| 状态 | 说明 |
|---|---|
suspended | 创建后或 yield 后 |
running | 正在执行 |
dead | 执行完毕或出错 |
normal | A resume 了 B,此时 A 处于 normal |
典型用法:把"每帧推进一点"的逻辑写成循环里 coroutine.yield(),宿主每帧 resume 一次——用同步写法表达异步流程,这是 Lua 在游戏里最好用的一点。
错误处理
| 方式 | 行为 |
|---|---|
error(msg) | 抛出错误 |
assert(v, msg) | v 为假时抛出 |
pcall(f, ...) | 捕获错误,返回 ok, result_or_err |
xpcall(f, handler) | 可带处理函数,常配合 debug.traceback |
与其他语言的差异速记
| 从…过来 | 最容易踩的点 |
|---|---|
| C/C++ / Java | 下标从 1 开始;~= 是不等于;没有 switch |
| Python | 没有列表/字典之分;and/or 返回操作数而非布尔 |
| JavaScript | a and b or c 是三元表达式的惯用写法,但 b 为假时会出错 |
性能经验
local化:全局查找走_G表,热循环里先local floor = math.floor- 表预分配:已知大小时避免 rehash(Lua 5.4 可用表构造提示)
- 字符串拼接用
table.concat - 避免在每帧路径上创建大量临时表——那是 GC 压力的主要来源,见 Lua GC
许可协议:CC BY
作者:Davids
本文链接:https://hustjjd.github.io/d33adc46.html
更新于:2026年10月10日