Lua 小白入门教程Lua 小白入门教程
首页
基础教程
实战进阶
编程指南
首页
基础教程
实战进阶
编程指南
  • 实战进阶

    • 🚀 实战进阶
    • 第1章 - 模块与包管理
    • 第2章 - 文件 I/O 操作
    • 第3章 - 错误处理
    • 第4章 - 面向对象编程
    • 第5章 - SpringBoot + Lua 整合实战 ⭐
    • 第6章 - Redis + Lua 脚本 ⭐
    • 第7章 - OpenResty 入门
    • 第8章 - 最佳实践与常见坑

第8章 - 最佳实践与常见坑

嗨,朋友!我是长安。

这是最后一章了!我把这些年在实际项目中踩过的坑和总结的经验,全部整理出来给你。这一章是"避坑指南",建议收藏!

🕳️ Java 程序员最容易踩的 10 个坑

坑1:数组索引从 1 开始

-- ❌ Java 思维
local arr = {"a", "b", "c"}
print(arr[0])    -- nil!不是 "a"!

-- ✅ Lua 正确写法
print(arr[1])    -- a

严重程度:⭐⭐⭐⭐⭐

这是 Java 程序员写 Lua 最最最容易犯的错误。一定要刻在脑子里:Lua 索引从 1 开始!

坑2:不等于是 ~= 不是 !=

-- ❌ Java 思维
if a != b then    -- 语法错误!

-- ✅ Lua 正确写法
if a ~= b then

严重程度:⭐⭐⭐⭐⭐

写了十年 != 的 Java 程序员,转到 Lua 几乎每次都会写错。

坑3:0 和空字符串是真值

-- ❌ Java/C 思维
local count = 0
if count then
    print("这会执行!")    -- 会执行!0 是真值!
end

-- ✅ 正确的判断方式
if count ~= 0 then
    print("count 不为零")
end

-- 同样,空字符串也是真值
local s = ""
if s then
    print("空字符串也是真的!")    -- 会执行!
end
if #s > 0 then
    print("字符串不为空")          -- 正确判断方式
end

严重程度:⭐⭐⭐⭐⭐

只有 nil 和 false 是假值,其他一切都是真值。这和 Java/JavaScript/Python 都不一样!

坑4:忘记写 local

-- ❌ 忘记 local,变成全局变量
function process()
    result = "hello"    -- 这是全局变量!会污染全局环境
end

-- ✅ 始终使用 local
function process()
    local result = "hello"    -- 局部变量,安全
end

严重程度:⭐⭐⭐⭐

Lua 默认是全局变量,和 Java(默认局部)完全相反。养成习惯,每个变量前面都加 local。

坑5:没有 continue

-- ❌ Java 思维
for i = 1, 10 do
    if i % 2 == 0 then
        continue    -- 语法错误!Lua 没有 continue
    end
    print(i)
end

-- ✅ 方案一:goto(推荐)
for i = 1, 10 do
    if i % 2 == 0 then goto continue end
    print(i)
    ::continue::
end

-- ✅ 方案二:if 包裹
for i = 1, 10 do
    if i % 2 ~= 0 then
        print(i)
    end
end

坑6:没有 ++ 和 +=

-- ❌ Java 思维
count++        -- 错误!
count += 1     -- 错误!

-- ✅ Lua 写法
count = count + 1

坑7:字符串拼接用 .. 不是 +

-- ❌ Java 思维
local s = "Hello" + " World"    -- 错误!+ 是算术运算

-- ✅ Lua 写法
local s = "Hello" .. " World"

-- 更要小心的是:
print("count: " + 5)    -- 报错!"count: " 不能转成数字
print("count: " .. 5)   -- 正确:count: 5
print("10" + 5)          -- 15(字符串自动转数字做运算)

坑8:/ 是浮点除法

-- ❌ Java 思维(以为是整数除法)
print(10 / 3)     -- 3.3333...(不是 3!)

-- ✅ 整数除法用 //
print(10 // 3)    -- 3

坑9:逻辑运算符是单词不是符号

-- ❌ Java 思维
if a && b then       -- 错误!
if a || b then       -- 错误!
if !a then           -- 错误!

-- ✅ Lua 写法
if a and b then
if a or b then
if not a then

坑10:Table 是引用类型,赋值不复制

-- ❌ 以为是值复制
local a = {1, 2, 3}
local b = a         -- b 和 a 指向同一个 table!
b[1] = 100
print(a[1])         -- 100(a 也被改了!)

-- ✅ 手动复制
local function copyTable(t)
    local copy = {}
    for k, v in pairs(t) do
        copy[k] = v
    end
    return copy
end
local c = copyTable(a)

Java 程序员应该理解

这其实和 Java 的引用类型一样。List<Integer> b = a; 也是引用赋值。但因为 Lua 没有类型声明,更容易犯这个错。

✅ Lua 编码规范

命名规范

-- 局部变量和函数:小驼峰(camelCase)
local userName = "长安"
local function getUserInfo() end

-- 常量:全大写 + 下划线
local MAX_RETRY = 3
local DEFAULT_TIMEOUT = 5000

-- 模块名:小写
local mymodule = require("mymodule")

-- "类"名:大驼峰(PascalCase)
local Animal = {}
local HttpClient = {}

-- 私有变量/函数:下划线前缀
local _privateVar = "secret"
local function _internalProcess() end

代码风格

-- 1. 始终使用 local
local x = 10

-- 2. 函数定义用 local function
local function foo()
end

-- 3. 字符串优先用双引号
local name = "长安"

-- 4. 表的最后一个元素也加逗号(方便增删)
local config = {
    host = "localhost",
    port = 8080,
    debug = true,     -- 最后也加逗号
}

-- 5. 善用提前返回,减少嵌套
local function validate(data)
    if not data then return false, "data is nil" end
    if not data.name then return false, "name is required" end
    if #data.name < 3 then return false, "name too short" end
    return true
end

🚀 性能优化技巧

1. 缓存全局函数到局部变量

-- ❌ 每次调用都要查全局表
for i = 1, 1000000 do
    math.sin(i)           -- 每次查找 math 表 → sin 函数
end

-- ✅ 缓存到局部变量(性能提升 30%+)
local sin = math.sin
for i = 1, 1000000 do
    sin(i)                -- 直接调用局部变量
end

2. 避免频繁创建临时 Table

-- ❌ 循环中创建大量临时 table
for i = 1, 100000 do
    local point = {x = i, y = i * 2}    -- 每次都创建新 table
    process(point)
end

-- ✅ 复用 table
local point = {}
for i = 1, 100000 do
    point.x = i
    point.y = i * 2
    process(point)
end

3. 字符串拼接用 table.concat

-- ❌ 大量字符串拼接(每次创建新字符串,类似 Java 的 String +)
local result = ""
for i = 1, 10000 do
    result = result .. "line " .. i .. "\n"
end

-- ✅ 用 table.concat(类似 Java 的 StringBuilder)
local parts = {}
for i = 1, 10000 do
    parts[#parts + 1] = "line " .. i
end
local result = table.concat(parts, "\n")

4. 预分配 Table 大小

-- 如果你知道 table 的大致大小,可以预先创建
-- LuaJIT 的 table.new 可以指定数组和哈希部分的大小
local ffi = require("ffi")
local tab_new = require("table.new")

local t = tab_new(1000, 0)    -- 预分配 1000 个数组位置
for i = 1, 1000 do
    t[i] = i
end

📋 Java ↔ Lua 速查对照表

操作JavaLua
打印System.out.println()print()
变量声明int x = 1local x = 1
字符串拼接+..
不等于!=~=
逻辑与&&and
逻辑或||or
逻辑非!not
自增i++i = i + 1
整数除法10 / 3 → 310 // 3 → 3
数组长度arr.length#arr
字符串长度str.length()#str
空值nullnil
注释//--
多行注释/* */--[[ ]]
代码块{ }do ... end 或 then ... end
for 循环for(int i=0;i<n;i++)for i=1,n do
for-eachfor(var x : list)for k,v in pairs(t) do
导入import xxxrequire("xxx")
三元运算符a ? b : ca and b or c
异常处理try-catchpcall/xpcall
创建对象new Object()setmetatable({}, Class)
this 引用thisself(通过 : 语法)

💡 长安的终极建议

  1. 先学好基础语法,再去碰 Redis Lua 和 OpenResty
  2. 多写多练,不要只看不动手
  3. 习惯差异,接受 Lua 和 Java 的不同(索引从1开始、~= 等)
  4. 善用 Table,它是 Lua 的万能工具
  5. 注意性能,缓存全局函数、用 table.concat 拼接字符串
  6. 安全第一,在 Java 中嵌入 Lua 一定要做沙箱
  7. 保持简单,Lua 的设计哲学就是简单,不要把它写成 Java

📝 全教程总结

恭喜你完成了整个 Lua 教程!🎉 让我们回顾一下你学到了什么:

基础部分

  • ✅ Lua 简介与环境搭建
  • ✅ 变量、数据类型、运算符
  • ✅ 流程控制(if/for/while)
  • ✅ 函数(多返回值、闭包)
  • ✅ Table(数组、字典、对象)
  • ✅ 字符串与模式匹配

进阶部分

  • ✅ 模块化与包管理
  • ✅ 文件 I/O
  • ✅ 错误处理(pcall/xpcall)
  • ✅ 面向对象编程(元表)
  • ✅ SpringBoot + Lua 整合
  • ✅ Redis + Lua 脚本实战
  • ✅ OpenResty 入门

你已经具备了在实际 Java 项目中使用 Lua 的能力。去实战吧!💪


由 编程指南 提供

最近更新: 2026/2/27 17:54
Contributors: 王长安
Prev
第7章 - OpenResty 入门