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.luaLua 编辑器
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::
endLua 流程控制
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) -- trueLua 函数
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)) -- 10Lua 运算符
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 8Lua 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()) -- 2Lua 协同程序(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. 密码不要硬编码在脚本中