Lua 教程 - 第十二章:最佳实践与优化
第十二章:最佳实践与优化
写出“能运行”的代码只是第一步,写出“高效、易读、易维护”的代码才是我们的目标。在本章,我们将总结 Lua 编程中的一些最佳实践和性能优化技巧。
12.1 代码风格与规范
良好的代码风格有助于团队协作和后期维护。
1. 局部变量优先
始终使用 local 声明变量,除非你确实需要全局变量。
-
性能:局部变量的访问速度比全局变量快得多。
-
安全:避免污染全局命名空间,减少变量冲突。
-
GC:局部变量的作用域结束时,引用解除,有利于垃圾回收。
-- Bad
count = 0
function inc() count = count + 1 end
-- Good
local count = 0
local function inc() count = count + 1 end
2. 命名约定
-
变量/函数:小写字母开头,驼峰命名 (e.g.,
userName,calculateTotal) 或下划线分隔 (e.g.,user_name,calculate_total)。保持一致即可。 -
常量:全大写,下划线分隔 (e.g.,
MAX_RETRY_COUNT)。 -
类/模块:大写字母开头 (e.g.,
HttpServer,StringUtil)。 -
私有成员:下划线开头 (e.g.,
_internalValue),这只是一种约定。
3. 注释
-
函数上方应说明功能、参数和返回值。
-
复杂逻辑代码块需要注释解释“为什么这么做”。
12.2 性能优化技巧
Lua 本身已经很快,但糟糕的代码会拖累性能。
1. 缓存全局变量
如果在循环或高频调用的函数中访问全局变量(包括标准库函数),应将其缓存为局部变量。
-- Bad
for i = 1, 1000000 do
x = math.sin(i)
end
-- Good
local sin = math.sin
for i = 1, 1000000 do
x = sin(i)
end
原因:访问局部变量只需读取栈或寄存器,而访问全局变量需要查找全局表(哈希表查找)。
2. 字符串拼接
在循环中进行大量字符串拼接时,使用 table.concat 而不是 ..。
-- Bad (产生大量中间字符串对象,增加 GC 压力)
local s = ""
for i = 1, 1000 do
s = s .. "a"
end
-- Good
local t = {}
for i = 1, 1000 do
t[#t + 1] = "a"
end
local s = table.concat(t)
3. 表的预分配
如果你知道表的大致大小,预先填充 nil 或者使用 C API 创建预分配大小的表(在纯 Lua 中较难做到,但可以通过构造器暗示)。
更重要的是,避免在循环中创建表。
-- Bad
for i = 1, 10000 do
local point = {x = i, y = i} -- 每次循环都创建新表
process(point)
end
-- Good (如果 process 不保存 point 的引用)
local point = {}
for i = 1, 10000 do
point.x = i
point.y = i
process(point)
end
4. 减少闭包创建
闭包(Closure)也是对象。在循环中创建函数会产生大量闭包实例。
-- Bad
for i = 1, 100 do
doSomething(function() return i end) -- 每次创建新闭包
end
-- Good (将函数移出循环,如果逻辑允许)
local function callback() ... end
for i = 1, 100 do
doSomething(callback)
end
12.3 安全编码
1. 防止注入
在拼接 SQL 语句或系统命令(os.execute)时,务必对用户输入进行过滤或转义,防止注入攻击。
2. 保护全局环境
可以使用 setmetatable(_G, {__newindex = ...}) 来监控或禁止全局变量的创建,防止意外拼写错误导致创建了全局变量。
local mt = {
__newindex = function(_, n)
error("attempt to write to undeclared variable " .. n, 2)
end,
__index = function(_, n)
error("attempt to read undeclared variable " .. n, 2)
end
}
setmetatable(_G, mt)
12.4 结语
Lua 是一门“小而美”的语言。它的简洁性赋予了开发者极大的自由,但自由也意味着责任。
通过本系列教程的学习,你已经掌握了 Lua 的核心语法、常用库、与 C 的交互以及实战技巧。但这只是开始,Lua 在游戏开发(OpenResty, Love2D)、嵌入式(NodeMCU)、工具脚本等领域还有广阔的天地等待你去探索。
Keep Coding, Keep Learning!
教程全系列完结。

