完整课程入口:996 全套课程体系 | Lua 学习路径 | 幂尔框架 mirs.cn
goto 在 Lua 5.2 起可用(996 部分新端跑 Lua 5.3/5.4,旧 5.1 端不适用,文末给替代写法)。三个场景收益直接:深层嵌套的错误提前跳出、状态机的状态跳转、循环内"类 continue"效果——Lua 原生没有 continue,goto 是官方认可的替代。
for i = 1, #players do
local p = players[i]
if not p.online then goto continue end
if p.level < 30 then goto continue end
-- 主体逻辑不再需要层层嵌套的 if
grantReward(p)
::continue::
end
标签 ::continue:: 放在循环体末尾,所有前置过滤直接跳过去,嵌套从三层压到一层。这个写法在 Lua 5.2+ 全版本可用,是官方手册认可的 continue 替代方案。
技能流程按阶段推进(抬手 → 判定 → 结算 → 收招),goto 让阶段切换一行完成:
::casting::
playAnim("cast")
if interrupted then goto done end
::hit::
if not calcHit() then goto done end
applyDamage()
::done::
cooldown = 1.5
相比 if-elseif 长链,每个状态独立成段,新增阶段不改旧分支。
错误清理路径也可以用 goto:出错时 goto cleanup,统一在 cleanup 段释放资源。三条语法红线要记住:标签只能在当前函数块内跳转;不能从外层跳进一个代码块内部(跳进局部变量的作用域会被编译器拒绝);标签可见范围止于所在代码块。
旧 5.1 端的等价替代:continue 场景用 repeat ... break true ... until true 包裹(break 跳出一次性循环体),状态机场景改用函数表 + state = stateTable[state] 的查表派发。两个写法语义等价,团队按引擎版本统一选一种即可。
goto 的滥用会让执行流像面条一样难追,两条守护规则保持可读性:标签命名表达意图(::continue::、::cleanup::、::done::),禁止 ::l1::、::l2:: 这类无意义命名;跳转只允许向前(跳过后续代码或跳到收尾段),向后跳转形成环路的场景一律改用 while 循环表达——循环是显式的环,goto 环是隐藏的环。排查手段:luac -l -l 输出的字节码里 goto 编译为 JMP 指令,看 JMP 的目标偏移就能确认有没有跨段乱跳。上线前用 luacheck 加上 --only 811 一类的循环检测项,配合 review 把关。goto 用在这三个场景是工具,用出第四种花样通常就是事故的开始。