Lua 教程

Lua 教程

Lua 是一门轻量小巧的脚本语言,以嵌入性著称,被广泛应用于游戏开发(魔兽世界、愤怒的小鸟)、嵌入式设备和应用脚本。

本教程包含

  • 基础篇:环境安装、编辑器、基本语法、数据类型、变量
  • 控制篇:循环、流程控制、函数、运算符
  • 数据篇:字符串、数组、迭代器、table(表)
  • 进阶篇:模块与包、元表、协同程序、文件 I/O、错误处理、调试、垃圾回收、面向对象

为什么学习 Lua

  • 轻量:解释器仅数百 KB,启动快
  • 可嵌入:C 语言 API 嵌入任何应用
  • 游戏脚本:大量游戏引擎使用
  • Nginx/Redis 的扩展脚本语言

特点

动态类型、table 万能数据结构
自动内存管理(垃圾回收)
函数是一等公民
协程支持并发协作

Lua 环境安装

Lua 环境安装

Lua 官方网站提供源码与各平台安装方式。

Linux 安装

# Ubuntu/Debian
sudo apt install lua5.4

# 或源码编译
curl -R -O https://www.lua.org/ftp/lua-5.4.7.tar.gz
tar zxf lua-5.4.7.tar.gz
cd lua-5.4.7
make linux test

macOS 安装

brew install lua

Windows 安装

# 方式1: 官方二进制包
# 方式2: 用 LuaBinaries(lua.org 或 GitHub)
# 方式3: scoop install lua / choco install lua

验证安装

lua -v
# Lua 5.4.7  Copyright (C) 1994-2024 Lua.org, PUC-Rio

交互模式

lua
> print("Hello")
> os.exit()

运行脚本

# hello.lua
print("Hello, Lua!")

lua hello.lua

LuaJIT(高性能版)

sudo apt install luajit    # 更快的 JIT 编译器
luajit script.lua

Lua 编辑器

Lua 编辑器

选择顺手的编辑器,配置 Lua 开发环境提升效率。

VS Code

1. 安装扩展 "Lua"(sumneko 出品)
2. 支持智能提示、语法高亮、调试
3. 配置 Lua 路径(settings.json)

"Lua.runtime.version": "Lua 5.4"

其他编辑器

ZeroBrane Studio   专业 Lua IDE(游戏开发常用)
IntelliJ + EmmyLua 插件
Sublime Text + 包
Vim/Neovim + lua 插件

调试工具

# Lua 自带调试库
debug.traceback()
debug.getinfo(1)

# 命令行断点调试(ZeroBrane Studio)

常用资源

官方文档: lua.org/manual
Lua 用户手册中文版
lua-users.org(社区教程)

运行环境组合

Lua + Love2D      游戏开发
Lua + Nginx       OpenResty 脚本
Lua + Redis       脚本扩展
Lua + Wireshark   抓包插件

Lua 基本语法

Lua 基本语法

Lua 语法简洁,与 C/Python 有相似之处但也有明显差异。

Hello World

print("Hello, World!")

程序结构

-- 单行注释
--[[ 多行注释
     支持换行 ]]

-- 变量与赋值
local x = 10          -- 局部变量(推荐)
y = 20                -- 全局变量
local a, b = 1, 2     -- 多变量赋值

-- 输出
print(x, y)

语句规则

1. 语句间无需分号(分号可选)
2. 大小写敏感
3. 关键字不能作变量名(if/end/function...)
4. 块用 end 结束(不是花括号)

代码块

if x > 10 then
    print("大于10")
end

for i = 1, 3 do
    print(i)
end

function add(a, b)
    return a + b
end

命名规范

变量/函数: 小写+下划线(my_var)
常量: 大写(MY_CONST)
全局变量: 慎用,避免命名冲突
local 声明局部变量,减少全局污染

Lua 数据类型

Lua 数据类型

Lua 是动态类型语言,有 8 种基本类型。

8 种类型

nil        空值(未赋值变量)
boolean    布尔 true/false
number     数值(整数+浮点)
string     字符串
table      表(万能数据结构)
function   函数
userdata   C 对象(宿主应用数据)
thread     协程

类型检查

print(type("hello"))   -- string
print(type(42))        -- number
print(type(true))      -- boolean
print(type(nil))       -- nil
print(type({}))        -- table
print(type(print))     -- function

local t = {}           -- 空表
print(type(t))         -- table

nil 与 boolean

local x                  -- x = nil
if x then print("真") end -- 不输出(nil 为假)

-- Lua 中只有 false 和 nil 为假,其余全真!
-- 注意: 0 和空字符串也是真!

number 类型

local i = 10            -- 整数
local f = 3.14          -- 浮点
local hex = 0xFF        -- 十六进制
local sci = 1e3         -- 1000.0
print(i + f)            -- 13.14

类型转换

tonumber("42")      -- 42
tonumber("3.14")    -- 3.14
tostring(42)        -- "42"
tostring(true)      -- "true"

Lua 变量

Lua 变量

Lua 变量分全局变量与局部变量,推荐尽量使用局部变量。

全局变量

a = 10          -- 全局变量(默认)
print(a)

-- 删除全局变量: 赋 nil
a = nil
print(a)        -- nil

局部变量(推荐)

local b = 20    -- 局部变量,作用域为当前块
do
    local c = 30     -- 仅在 do...end 内有效
end
-- print(c)     -- 报错: c 不存在

多变量赋值

local a, b = 1, 2        -- a=1, b=2
local x, y = 10          -- x=10, y=nil
local p, q = 1, 2, 3     -- 多余值忽略: p=1, q=2

-- 交换变量
local m, n = 1, 2
m, n = n, m              -- m=2, n=1

赋值顺序

-- 先求值再赋值
local i = 0
i, i2 = i + 1, i + 2    -- i=1, i2=2(用旧值计算)

变量作用域

局部变量作用域: 声明位置到所在块结束
-- 优先使用 local: 性能好、避免命名冲突
-- 模块内常用 local function 定义私有函数

Lua 循环

Lua 循环

Lua 提供 while、for(数值与泛型)和 repeat-until 三种循环。

while 循环

local i = 1
while i <= 5 do
    print(i)
    i = i + 1
end

数值 for 循环

-- for 变量 = 初值, 终值, 步长 do
for i = 1, 5 do
    print(i)          -- 1 2 3 4 5
end

for i = 5, 1, -1 do
    print(i)          -- 5 4 3 2 1
end

for i = 1, 10, 2 do
    print(i)          -- 1 3 5 7 9
end

泛型 for(遍历表)

local days = {"一", "二", "三"}

for i, v in ipairs(days) do    -- 数组索引遍历
    print(i, v)
end

local person = {name = "Alice", age = 25}
for k, v in pairs(person) do   -- 键值遍历(顺序不保证)
    print(k, v)
end

repeat-until

local n = 1
repeat
    print(n)
    n = n + 1
until n > 3        -- 条件为真退出(至少执行一次)

break 与 return

for i = 1, 10 do
    if i == 3 then
        break          -- 跳出循环
    end
end

-- Lua 没有 continue,可用条件跳过或 goto(Lua 5.2+)

goto(5.2+)

for i = 1, 5 do
    if i == 2 then
        goto skip      -- 模拟 continue
    end
    print(i)
    ::skip::
end

Lua 流程控制

Lua 流程控制

Lua 的流程控制有 if-elseif-else 结构,以 end 结束。

if 语句

local score = 85

if score >= 90 then
    print("优秀")
elseif score >= 60 then
    print("及格")
else
    print("不及格")
end

嵌套 if

local x, y = 1, 2
if x > 0 then
    if y > 0 then
        print("第一象限")
    end
end

条件表达式

-- 逻辑运算符: and / or / not
local a, b = true, false
print(a and b)     -- false
print(a or b)      -- true
print(not a)       -- false

-- 短路求值: or 返回第一个真值
local name = nil
print(name or "默认值")    -- 默认值

-- 三元表达式模拟
local max = (x > y) and x or y

真假判断

-- Lua 中只有 false 和 nil 为假!
if 0 then print("真") end          -- 输出(0 为真)
if "" then print("真") end         -- 输出(空串为真)
if nil then print("真") end        -- 不输出
if false then print("真") end      -- 不输出

比较运算

==  ~=  <  >  <=  >=
-- 注意: 不等于是 ~=(不是 !=)
print(1 ~= 2)   -- true

Lua 函数

Lua 函数

Lua 函数是一等公民:可赋值、传参、作为返回值。

定义与调用

function add(a, b)
    return a + b
end

print(add(1, 2))      -- 3

-- 等价写法(变量指向函数)
local sub = function(a, b)
    return a - b
end

多返回值

function divmod(a, b)
    return math.floor(a / b), a % b
end

local q, r = divmod(10, 3)
print(q, r)          -- 3 1

可变参数

function sum(...)
    local total = 0
    for _, v in ipairs({...}) do
        total = total + v
    end
    return total
end

print(sum(1, 2, 3))      -- 6
print(sum(1, 2, 3, 4))   -- 10

闭包

function counter()
    local count = 0
    return function()
        count = count + 1
        return count
    end
end

local c = counter()
print(c())   -- 1
print(c())   -- 2
print(c())   -- 3

尾调用

function f(n)
    if n <= 0 then return n end
    return f(n - 1)     -- 尾调用(优化栈)
end

函数作为参数(回调)

function apply(func, value)
    return func(value)
end

print(apply(function(x) return x * 2 end, 5))   -- 10

Lua 运算符

Lua 运算符

Lua 提供算术、关系、逻辑、连接等运算符。

算术运算符

+  加   -  减   *  乘
/  除   %  取余   ^  幂
// 整除(Lua 5.3+)

print(7 / 2)      -- 3.5
print(7 // 2)     -- 3(整除)
print(7 % 3)      -- 1
print(2 ^ 10)     -- 1024.0

关系运算符

== 等于   ~= 不等于
<  >  <=  >=  比较

print(1 == 1)      -- true
print(1 ~= 2)      -- true
print("a" < "b")   -- true(字符串比较)

逻辑运算符

and  与(短路)
or   或(短路)
not  非

print(true and false)    -- false
print(1 and 2)           -- 2(都真返回最后一个)
print(nil or "默认")      -- 默认
print(not true)          -- false

字符串连接

local s = "Hello" .. " " .. "Lua"
print(s)          -- Hello Lua

print(1 .. 2)     -- 12(数字自动转字符串)

长度与索引

#    取长度
[]   索引访问

print(#"hello")       -- 5
local t = {1, 2, 3}
print(#t)             -- 3
print(t[1])           -- 1

运算符优先级

^ 最高
not  #  -
*  /  //  %
+  -
.. 连接
<  >  <=  >=  ~=  ==
and
or 最低

Lua 字符串

Lua 字符串

Lua 字符串不可变,支持丰富的处理函数。

字符串表示

local s1 = "双引号"
local s2 = '单引号'
local s3 = [[多行
字符串]]        -- 长括号(不转义)

local s4 = "换行
制表	"
local path = "C:\Users\admin"

常用方法

local s = "Hello Lua"

#s              -- 9 长度
string.upper(s) -- HELLO LUA
string.lower(s) -- hello lua
string.rep("ab", 3)     -- ababab
string.reverse(s)       -- auL olleH
string.sub(s, 1, 5)     -- Hello
string.format("%d-%s", 42, "ok")  -- 42-ok

查找与替换

local s = "hello world"
string.find(s, "world")      -- 7 11
string.find(s, "l+")         -- 3 4(模式匹配)

string.gsub("a1b2", "%d", "#")   -- a#b#  替换数字
string.match("age=25", "%d+")    -- 25  提取

模式匹配(类似正则)

%d  数字    %a  字母    %s  空白
.   任意    +  一个或多个   *  零或多个
^   开头    $  结尾

string.match("hello123", "%a+")    -- hello
string.match("2026-08-18", "%d+")  -- 2026

字符与编码

string.byte("A")     -- 65
string.char(65)      -- A
string.len("中文")    -- 6(UTF-8 三字节/字)

字符串拼接注意

-- 循环拼接用 table.concat 高效
local parts = {}
for i = 1, 100 do
    parts[i] = tostring(i)
end
local result = table.concat(parts, ",")

Lua 数组

Lua 数组

Lua 数组用 table 实现,索引从 1 开始(与 C 不同!)。

创建数组

-- 方式1: 直接初始化
local arr = {"a", "b", "c"}

-- 方式2: 逐个赋值
local nums = {}
nums[1] = 10
nums[2] = 20
nums[3] = 30

访问元素

local arr = {"a", "b", "c"}
print(arr[1])     -- a(注意从1开始!)
print(arr[3])     -- c
print(arr[0])     -- nil(0不是数组起点)

-- 修改
arr[2] = "B"
print(arr[2])     -- B

数组长度

local arr = {1, 2, 3, 4, 5}
print(#arr)       -- 5
print(table.getn(arr))   -- 5(旧版)

遍历数组

-- 数值 for
for i = 1, #arr do
    print(i, arr[i])
end

-- ipairs(推荐: 遇到 nil 停止)
for i, v in ipairs(arr) do
    print(i, v)
end

插入与删除

local t = {1, 2, 3}
table.insert(t, 4)          -- {1,2,3,4} 末尾
table.insert(t, 1, 0)       -- {0,1,2,3,4} 指定位置
table.remove(t)             -- 删除末尾 {0,1,2,3}
table.remove(t, 1)          -- 删除第1个 {1,2,3}

排序

local nums = {3, 1, 4, 1, 5}
table.sort(nums)            -- 升序
table.sort(nums, function(a, b) return a > b end)  -- 降序

Lua 迭代器

Lua 迭代器

迭代器用于遍历集合,Lua 支持泛型 for 与自定义迭代器。

内置迭代器

-- ipairs: 遍历数组(1..n 连续)
for i, v in ipairs({10, 20, 30}) do
    print(i, v)
end

-- pairs: 遍历所有键值(含哈希部分,顺序不定)
local t = {name = "Alice", age = 25, [1] = "one"}
for k, v in pairs(t) do
    print(k, v)
end

自定义迭代器(闭包)

function range(n)
    local i = 0
    return function()
        i = i + 1
        if i <= n then return i end
    end
end

for v in range(3) do
    print(v)          -- 1 2 3
end

泛型 for 原理

for var1, var2 in iterator, state, init do
    -- 每次调用 iterator(state, var1),直到返回 nil
end

状态迭代器(带控制变量)

function iter(state, i)
    i = i + 1
    if i <= state.n then return i, state[i] end
end

local t = {"a", "b", "c"}
for i, v in iter, t, 0 do
    print(i, v)       -- 1 a  2 b  3 c
end

多状态迭代器示例

-- 斐波那契迭代器
function fib_iter(n)
    local a, b, i = 0, 1, 0
    return function()
        if i < n then
            i = i + 1
            a, b = b, a + b
            return a
        end
    end
end

for v in fib_iter(6) do print(v) end  -- 1 1 2 3 5 8

Lua table(表)

Lua table(表)

table 是 Lua 唯一的数据结构,可作数组、字典、对象、模块等一切容器。

创建表

-- 空表
local t = {}

-- 数组风格
local arr = {"a", "b", "c"}

-- 字典风格
local person = {name = "Alice", age = 25}

-- 混合
local mixed = {1, 2, x = 10, [3] = "three"}

访问元素

local person = {name = "Alice", age = 25}

print(person.name)      -- Alice(点号)
print(person["name"])   -- Alice(中括号)
print(person.age)       -- 25

-- 变量键
local key = "name"
print(person[key])      -- Alice

新增与删除

person.city = "北京"     -- 新增
person.age = nil         -- 删除(赋 nil)

-- 判断键是否存在
if person.city ~= nil then print("有城市") end

遍历

for k, v in pairs(person) do
    print(k, v)
end

-- 数组部分用 ipairs(按顺序)
local arr = {10, 20, 30}
for i, v in ipairs(arr) do print(i, v) end

嵌套表

local student = {
    name = "Bob",
    scores = {math = 90, english = 85},
}

print(student.scores.math)     -- 90
print(student["scores"]["english"])  -- 85

table 常用函数

table.insert(t, v)      -- 追加
table.remove(t, i)      -- 删除
table.sort(t)           -- 排序
table.concat(t, sep)    -- 连接
table.unpack(t)         -- 展开为返回值
#t                      -- 长度

注意

# 只对连续数组部分可靠
nil 元素会让 # 和 ipairs 表现异常

Lua 模块与包

Lua 模块与包

模块是代码组织的基本单元,通过 table 实现,require 加载。

定义模块

-- mymath.lua
local M = {}

function M.add(a, b)
    return a + b
end

function M.sub(a, b)
    return a - b
end

M.PI = 3.14159

return M

加载模块

-- main.lua
local mymath = require("mymath")

print(mymath.add(1, 2))     -- 3
print(mymath.PI)            -- 3.14159

模块搜索路径

-- package.path 决定查找路径
print(package.path)
-- 默认: ./?.lua; /usr/local/share/lua/5.4/?.lua; ...

-- 自定义路径
package.path = package.path .. ";/opt/mylua/?.lua"
local mymod = require("mymod")

require 特性

1. 只加载一次(缓存于 package.loaded)
2. 重复 require 返回缓存
3. 加载失败抛错

-- 手动清除缓存可重新加载
package.loaded["mymath"] = nil
require("mymath")

模块内部私有函数

local M = {}

-- 私有(不导出)
local function helper(x)
    return x * 2
end

-- 公开
function M.double(x)
    return helper(x)
end

return M

标准库模块

string  字符串操作
table   表操作
math    数学函数
io      文件输入输出
os      操作系统接口
utf8    UTF-8 支持(5.3+)
coroutine 协程

Lua 元表(Metatable)

Lua 元表(Metatable)

元表是 Lua 的高级特性,定义 table 的特殊行为(运算符重载、继承、默认值)。

setmetatable / getmetatable

local t = {}
local mt = {}

setmetatable(t, mt)
print(getmetatable(t) == mt)   -- true

__index: 表继承

local parent = {name = "父类", greet = function() print("你好") end}

local child = {}
setmetatable(child, {__index = parent})

print(child.name)    -- 父类(查不到时找元表)
child.greet()        -- 你好

-- 注意: __index 也可为函数
setmetatable(child, {__index = function(t, k)
    return "默认值:" .. k
end})
print(child.anything)   -- 默认值:anything

__newindex: 拦截赋值

local t = {}
local log = {}
setmetatable(t, {
    __newindex = function(tbl, key, value)
        print("设置 " .. key .. " = " .. value)
        rawset(tbl, key, value)
    end,
})

t.x = 10   -- 设置 x = 10

运算符重载

local Vector = {}
Vector.__add = function(a, b)
    return {x = a.x + b.x, y = a.y + b.y}
end

local v1 = {x = 1, y = 2}
local v2 = {x = 3, y = 4}
setmetatable(v1, Vector)
setmetatable(v2, Vector)

local v3 = v1 + v2     -- 触发 __add
print(v3.x, v3.y)      -- 4 6

__tostring: 自定义输出

local person = {name = "Alice", age = 25}
setmetatable(person, {
    __tostring = function(t)
        return t.name .. "(" .. t.age .. "岁)"
    end,
})

print(person)   -- Alice(25岁)

__call: 表当函数调用

local counter = {value = 0}
setmetatable(counter, {
    __call = function(t)
        t.value = t.value + 1
        return t.value
    end,
})

print(counter())   -- 1
print(counter())   -- 2

Lua 协同程序(coroutine)

Lua 协同程序(coroutine)

协程实现协作式多任务,可暂停与恢复执行,用于生成器、状态机等。

基础用法

-- 创建协程
local co = coroutine.create(function()
    print("协程开始")
    coroutine.yield()          -- 暂停
    print("协程恢复")
end)

print(coroutine.status(co))    -- suspended
coroutine.resume(co)           -- 协程开始(执行到 yield)
print(coroutine.status(co))    -- suspended
coroutine.resume(co)           -- 协程恢复
print(coroutine.status(co))    -- dead

yield 传值

local co = coroutine.create(function(a)
    print("收到: " .. a)
    local b = coroutine.yield(a * 2)   -- 返回给 resume,接收下次 resume 参数
    print("再次收到: " .. b)
    return a + b
end)

print(coroutine.resume(co, 10))   -- 收到:10  true 20
print(coroutine.resume(co, 5))    -- 再次收到:5  true 15

生成器(迭代器)

function gen()
    for i = 1, 5 do
        coroutine.yield(i)
    end
end

local co = coroutine.create(gen)
while coroutine.status(co) ~= "dead" do
    local ok, v = coroutine.resume(co)
    if ok and v then print(v) end
end
-- 1 2 3 4 5

coroutine.wrap(简化)

local iter = coroutine.wrap(function()
    for i = 1, 3 do coroutine.yield(i) end
end)

print(iter())   -- 1
print(iter())   -- 2
print(iter())   -- 3

状态与函数

coroutine.create(f)   创建(返回协程)
coroutine.resume(co)  恢复/启动(返回 ok, 值)
coroutine.yield(...)  暂停并返回值
coroutine.status(co)  suspended/running/dead
coroutine.wrap(f)     返回函数式接口
coroutine.running()   当前协程

应用场景

异步流程控制(协作式)
状态机与游戏 AI
生成器与流式处理
多任务调度

Lua 文件 I/O

Lua 文件 I/O

Lua 的 io 库提供简单与完整两种文件操作方式。

简单模式(常用)

-- 写文件
local file = io.open("data.txt", "w")
file:write("第一行
")
file:write("第二行
")
file:close()

-- 读文件(全部)
local f = io.open("data.txt", "r")
local content = f:read("*a")    -- *a 读全部
f:close()
print(content)

-- 逐行读
local f = io.open("data.txt", "r")
for line in f:lines() do
    print(line)
end
f:close()

完整模式

local file = io.open("data.txt", "a")    -- 追加模式
file:write("追加内容
")
file:close()

读取格式

f:read("*a")    -- 全部
f:read("*l")    -- 一行(默认)
f:read("*n")    -- 一个数字
f:read(10)      -- 10 个字节
f:read("*L")    -- 一行(含换行)
-- 读数字示例
local f = io.open("nums.txt", "r")
local a = f:read("*n")
local b = f:read("*n")
f:close()

文件模式

"r"  只读
"w"  写入(清空)
"a"  追加
"r+" 读写
"w+" 读写(清空)
"a+" 读写(追加)
"b"  二进制模式(rb/wb)

其他 io 函数

io.write(...)      标准输出
io.read()          标准输入
io.lines(path)     迭代读行
io.tmpfile()       临时文件
os.rename(a, b)    重命名
os.remove(path)    删除

Lua 错误处理

Lua 错误处理

Lua 通过 error 抛错、pcall/xpcall 捕获错误。

错误抛出

error("出错了")            -- 抛错误并终止
error("参数错误", 2)       -- 第2参数指定错误位置层级
assert(条件, "消息")      -- 条件为假则报错

function divide(a, b)
    assert(b ~= 0, "除数不能为 0")
    return a / b
end

pcall 捕获错误

local ok, result = pcall(function()
    error("模拟错误")
end)

if ok then
    print("成功:", result)
else
    print("失败:", result)    -- 失败: 模拟错误
end

xpcall 带错误追踪

local ok, err = xpcall(function()
    error("出问题")
end, debug.traceback)   -- 错误处理函数

print(ok)      -- false
print(err)     -- 含调用栈信息

保护调用模式

-- 封装: 安全调用任意函数
function safe_call(func, ...)
    local args = {...}
    local ok, result = pcall(function()
        return func(table.unpack(args))
    end)
    if not ok then
        print("调用失败: " .. tostring(result))
        return nil
    end
    return result
end

错误处理最佳实践

1. 边界用 assert 快速失败
2. 可恢复错误用 pcall 捕获
3. 模块内部抛错带上清晰消息
4. 使用 error 的 level 参数定位错误源

Lua 调试(Debug)

Lua 调试(Debug)

Lua 的 debug 库提供运行时检查与调试能力。

基础调试函数

debug.traceback()         -- 当前调用栈字符串
debug.getinfo(1)          -- 调用信息表
debug.getlocal(1, 1)      -- 局部变量
debug.getupvalue(f, 1)    -- 闭包上值

-- 打印调用栈
print(debug.traceback("堆栈:"))

获取函数信息

local info = debug.getinfo(1)
print(info.source)     -- 源码位置
print(info.currentline)
print(info.short_src)

-- 列出局部变量
local x, y = 1, 2
for i = 1, 100 do
    local name, value = debug.getlocal(1, i)
    if not name then break end
    print(name, value)   -- x 1  y 2
end

断言与测试

-- 简单断言(可替代用)
function check(cond, msg)
    if not cond then
        error(msg or "断言失败", 2)
    end
end

check(1 + 1 == 2, "数学坏了!")

性能分析与测试工具

-- 简单计时
local t0 = os.clock()
-- 执行代码
print("耗时:", os.clock() - t0)

-- LuaProfiler / luacov 等第三方工具

调试技巧

1. print + debug.traceback 快速定位
2. 复杂问题用 ZeroBrane 断点调试
3. 线上问题加日志点
4. 检查 nil 访问(最常见错误)

Lua 垃圾回收

Lua 垃圾回收

Lua 自动管理内存(垃圾回收),也可手动控制 GC 节奏。

自动回收

-- 无需手动释放,GC 自动清理不再使用的对象
local t = {}
t = nil          -- 表失去引用,等待回收

collectgarbage 控制

collectgarbage("collect")     -- 执行完整回收
collectgarbage("count")       -- 内存用量(KB)
collectgarbage("stop")        -- 停止自动 GC
collectgarbage("restart")     -- 恢复自动 GC
collectgarbage("step", 100)   -- 增量回收
collectgarbage("setpause", 200)   -- 调整触发参数
collectgarbage("setstepmul", 200)

查看内存

-- 打印当前内存(KB)
print(collectgarbage("count"))

-- 多次强制回收后测真实占用
collectgarbage("collect")
collectgarbage("collect")
print(collectgarbage("count"))

弱引用表(weak table)

-- __mode: "k"键弱引用, "v"值弱引用, "kv"都弱
local cache = {}
setmetatable(cache, {__mode = "v"})   -- 值可被回收

cache["data"] = {}        -- 放入无引用对象
collectgarbage("collect")
print(cache["data"])      -- nil(已被回收)

-- 应用: 缓存、对象池、观察者列表

GC 最佳实践

1. 避免循环引用(或用弱表)
2. 大对象及时置 nil
3. 游戏循环中控制 GC 节奏(分步回收)
4. 用弱表实现缓存防内存泄漏

Lua 面向对象

Lua 面向对象

Lua 没有 class 关键字,通过 table + 元表实现面向对象(继承、封装、多态)。

简单类(构造函数)

-- 类定义(本质是表)
Person = {}
Person.__index = Person

-- 构造函数
function Person.new(name, age)
    local self = setmetatable({}, Person)
    self.name = name
    self.age = age
    return self
end

-- 方法
function Person:greet()          -- 冒号自动传 self
    print("你好,我是" .. self.name)
end

-- 使用
local p = Person.new("Alice", 25)
p:greet()          -- 你好,我是Alice
print(p.name)      -- Alice

冒号 vs 点号

function Person:greet()          -- 等价于
function Person.greet(self)      -- 自动注入 self

p:greet()       -- 等价于
p.greet(p)

继承

Student = {}
setmetatable(Student, {__index = Person})   -- 继承 Person
Student.__index = Student

function Student.new(name, age, grade)
    local self = Person.new(name, age)      -- 调用父类构造
    setmetatable(self, Student)
    self.grade = grade
    return self
end

function Student:greet()
    print(self.name .. "是" .. self.grade .. "年级学生")
end

local s = Student.new("Bob", 10, 5)
s:greet()    -- Bob是5年级学生(多态)
print(s.age) -- 10(继承属性)

封装(私有成员)

function Counter.new()
    local count = 0        -- 闭包私有变量
    return {
        inc = function() count = count + 1 end,
        get = function() return count end,
    }
end

local c = Counter.new()
c.inc(); c.inc()
print(c.get())   -- 2
print(c.count)   -- nil(外部无法访问)

多重继承(元表链)

-- 用 __index 函数查找多个父类
setmetatable(Child, {
    __index = function(t, k)
        local v = ParentA[k]
        if v == nil then v = ParentB[k] end
        return v
    end,
})

Lua 数据库访问

Lua 数据库访问

Lua 通过库访问数据库,常用 LuaSQL(MySQL/PostgreSQL/SQLite)。

安装 LuaSQL

# LuaRocks 包管理器
luarocks install luasql-sqlite3
luarocks install luasql-mysql

SQLite 访问

local luasql = require("luasql.sqlite3")

-- 打开环境
local env = luasql.sqlite3()

-- 连接数据库
local conn = env:connect("test.db")

-- 建表与插入
conn:execute([[CREATE TABLE IF NOT EXISTS users(
    id INTEGER PRIMARY KEY,
    name TEXT
)]])
conn:execute([[INSERT INTO users(name) VALUES('Alice')]])

-- 查询
local cursor = conn:execute("SELECT id, name FROM users")
local row = cursor:fetch({}, "a")    -- 按名访问
while row do
    print(row.id, row.name)
    row = cursor:fetch({}, "a")
end

-- 关闭
cursor:close()
conn:close()
env:close()

MySQL 访问

local luasql = require("luasql.mysql")
local env = luasql.mysql()
local conn = env:connect("mydb", "root", "pass", "localhost", 3306)

local cursor = conn:execute("SELECT * FROM users")
local row = cursor:fetch({}, "a")
while row do
    print(row.id, row.name)
    row = cursor:fetch({}, "a")
end

conn:close()
env:close()

其他数据库方案

Redis:  redis-lua
MongoDB: lua-mongo
ODBC:   luasql-odbc
PostgreSQL: luasql-postgres

安全提示

1. 拼接 SQL 时注意防注入
2. 使用参数化/转义函数
3. 连接用完及时关闭
4. 密码不要硬编码在脚本中
第 1 / 23 节