Lua 概览

自动关联目录:Lua 概览

一门语言值不值得投入,看的是它把复杂度放在哪里。Lua 的选择是:把复杂度交给使用者,换一个极小、极快、极易嵌入的内核。

设计取舍

取舍换来什么代价
只有 table 一种数据结构内核极小,语义统一数组/字典/对象靠约定区分
没有内建类系统面向对象可以自由实现每个项目一套写法
动态类型 + 解释执行热更新、快速迭代运行时开销与类型不安全
不提供多线程无锁,实现简单并发靠协程或多 VM
ANSI C 实现到处都能编译嵌入性能上限低于 JIT 语言

八种类型

类型说明
nil空,全局变量默认值;也是"删除"的语义
boolean只有 nil 和 false 为假,0 和空串是真
number5.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 / __lenprint / #
__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执行完毕或出错
normalA 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 返回操作数而非布尔
JavaScripta and b or c 是三元表达式的惯用写法,但 b 为假时会出错

性能经验

  • local 化:全局查找走 _G 表,热循环里先 local floor = math.floor
  • 表预分配:已知大小时避免 rehash(Lua 5.4 可用表构造提示)
  • 字符串拼接用 table.concat
  • 避免在每帧路径上创建大量临时表——那是 GC 压力的主要来源,见 Lua GC