Lua 循环:让程序自动“重复做对的事”
在编程的世界里,重复是常态。无论是处理数据、遍历列表,还是等待用户输入,我们总需要让程序“重复执行一段代码”。Lua 语言通过简洁而强大的循环机制,帮助开发者高效完成这类任务。今天,我们就来深入聊聊 Lua 循环,从基础语法到实战技巧,手把手带你掌握这一核心功能。
如果你刚接触编程,可能会觉得“循环”听起来很抽象。不妨把它想象成一个自动洗衣机:你把衣服放进去,设定好时间,它就会自动完成清洗、漂洗、脱水等一系列动作。而 Lua 循环,就是你写下的那串指令,它会自动重复执行,直到你设定的条件满足为止。
for 循环:计数型循环的精准控制
Lua 中最常用的循环结构之一是 for 循环,它特别适合你知道循环次数的场景。比如你要打印 1 到 10 的数字,或者遍历一个固定长度的数组。
-- 从 1 循环到 10,每次递增 1
for i = 1, 10, 1 do
print("当前数字是:" .. i)
end
上面这段代码中:
i = 1是循环变量的初始值,相当于洗衣机开始运转前的设定。10是循环的结束条件,当 i 超过 10 时,循环停止。1是步长,表示每次 i 增加多少。默认步长是 1,可以省略。
如果你想要倒序输出,比如从 10 到 1,只需要把步长改为 -1:
-- 倒序输出 10 到 1
for i = 10, 1, -1 do
print("倒计时:" .. i)
end
for 循环的灵活性
for 循环不仅限于整数。你还可以使用浮点数作为步长,比如打印 0.1 到 1.0 的小数:
-- 打印 0.1 到 1.0,步长为 0.1
for i = 0.1, 1.0, 0.1 do
print("数值:" .. i)
end
这种写法在处理物理计算、动画帧、时间轴等场景非常有用。
while 循环:条件驱动的“持续运行”
当循环次数不确定时,while 循环就派上用场了。它的核心思想是:只要条件为真,就继续执行;一旦条件变为假,就退出循环。
-- 简单的猜数字游戏
local secret_number = 42
local guess = 0
while guess ~= secret_number do
print("请输入一个数字:")
guess = tonumber(io.read()) -- 从控制台读取输入
if guess < secret_number then
print("太小了!")
elseif guess > secret_number then
print("太大了!")
else
print("恭喜你,猜对了!")
end
end
这段代码中:
guess ~= secret_number是判断条件,表示“如果猜的数不等于正确答案”。io.read()用于读取用户输入,tonumber()将字符串转换为数字。- 循环会一直持续,直到用户猜中为止。
while 循环的陷阱与防范
一个常见的错误是忘记更新循环变量,导致无限循环。比如下面这段代码:
-- ❌ 错误示例:缺少更新逻辑
local i = 1
while i <= 5 do
print(i)
-- 没有 i = i + 1,循环永远无法结束!
end
这个程序会卡死,一直打印 1。因此,使用 while 循环时,务必确保条件最终能变为假。
repeat...until 循环:先执行再判断
repeat...until 是 Lua 中一个非常独特的循环结构,它的特点是:先执行一次,再判断条件。这在需要至少执行一次的场景中特别有用。
-- 用户输入验证:必须输入非空内容
local input = ""
repeat
print("请输入你的名字:")
input = io.read()
until input ~= "" -- 直到输入非空才退出
print("你好," .. input .. "!")
与 while 不同,repeat...until 保证至少执行一次。这就像你去餐厅点菜,服务员必须先问你“要吃什么”,然后才判断你有没有回答。
与 while 循环的对比
| 特性 | while 循环 | repeat...until 循环 |
|---|---|---|
| 执行顺序 | 先判断条件,再执行 | 先执行,再判断条件 |
| 至少执行一次 | 否 | 是 |
| 适合场景 | 条件明确,可能不执行 | 必须至少执行一次 |
遍历表(table)的循环:处理数据集合
在 Lua 中,table 是最核心的数据结构,类似于 Python 的字典或 JavaScript 的对象。我们经常需要遍历一个 table 中的所有键值对。
ipairs:遍历有序表
当你有一个编号从 1 开始的数组式 table 时,使用 ipairs 是最佳选择:
-- 定义一个学生名单
local students = {"小明", "小红", "小刚", "小丽"}
-- 使用 ipairs 遍历
for index, name in ipairs(students) do
print("第 " .. index .. " 位学生是:" .. name)
end
输出:
第 1 位学生是:小明
第 2 位学生是:小红
第 3 位学生是:小刚
第 4 位学生是:小丽
ipairs 会从下标 1 开始,逐个获取键值对,直到遇到 nil 为止。
pairs:遍历所有键值对
如果你的 table 不是连续编号,或者包含字符串键,应该使用 pairs:
-- 定义一个成绩表
local scores = {
["语文"] = 85,
["数学"] = 92,
["英语"] = 78,
["物理"] = 88
}
-- 使用 pairs 遍历所有键值对
for subject, score in pairs(scores) do
print(subject .. " 成绩:" .. score)
end
输出:
语文 成绩:85
数学 成绩:92
英语 成绩:78
物理 成绩:88
注意:pairs 的遍历顺序是不确定的,不要依赖顺序。
实际案例:统计学生成绩
我们来做一个小项目:计算平均分并找出最高分。
local scores = {
["小明"] = 85,
["小红"] = 92,
["小刚"] = 78,
["小丽"] = 88
}
local total = 0
local max_score = 0
local best_student = ""
for name, score in pairs(scores) do
total = total + score
if score > max_score then
max_score = score
best_student = name
end
end
local average = total / #scores -- #scores 获取表中元素个数
print("平均分:" .. average)
print("最高分:" .. max_score .. "(由 " .. best_student .. " 获得)")
这段代码展示了如何结合 pairs 和变量更新,完成一个完整的数据处理任务。
循环控制语句:跳出与跳过
Lua 提供了两个控制语句,让你更灵活地管理循环流程:
break:立即退出当前循环continue:跳过本次循环,进入下一次(Lua 中通过goto实现,但通常用if跳过)
break 的使用场景
当你在循环中发现某个条件满足,不需要继续执行时,可以用 break。
-- 找到第一个能被 3 整除的数
for i = 1, 100 do
if i % 3 == 0 then
print("第一个能被 3 整除的数是:" .. i)
break -- 找到后立即退出
end
end
模拟 continue:跳过特定情况
Lua 没有 continue 关键字,但可以通过嵌套 if 实现跳过:
-- 打印 1 到 10,但跳过 5
for i = 1, 10 do
if i == 5 then
-- 跳过 5,不执行下面的 print
goto continue
end
print("当前数字:" .. i)
::continue::
end
⚠️ 注意:
goto标签必须在同级作用域中定义,且::continue::必须在if语句之后。
总结:掌握 Lua 循环的关键
Lua 循环是编写高效、可维护代码的基础。通过 for、while、repeat...until 三种结构,你可以应对几乎所有重复执行的场景。而 ipairs 和 pairs 则让你轻松处理数据集合。
记住几个核心原则:
- 用
for处理已知次数的循环 - 用
while处理条件驱动的重复 - 用
repeat...until确保至少执行一次 - 遍历 table 时选择合适的迭代器
- 合理使用
break控制流程
编程的本质,就是让机器替你重复做对的事。当你熟练掌握 Lua 循环,你就真正拥有了让程序“自动工作”的能力。不妨现在就动手写一个小程序,用循环计算 1 到 100 的和,或者实现一个简易的菜单系统——实践,是最好的老师。