在 Lua 中,for
和 while
是两种核心的循环结构,用于实现重复执行逻辑。以下是它们的详细用法、进阶技巧及注意事项:
在 Lua 中,`for` 和 `while` 是两种核心的循环结构的详细用法—目录
一、for
循环
1. 数值 for
循环
基础语法:
-- 格式:for var = start, end [, step] do ... end
for i = 1, 5 do
print(i) -- 输出 1 到 5
end
for i = 10, 1, -2 do
print(i) -- 输出 10,8,6,4,2
end
关键特性:
• 范围表达式:start
、end
和 step
均为表达式,运行时计算。
• 隐式步长:默认步长为 1
。
• 浮点数支持:
for i = 0, 1, 0.2 do
print(i) -- 输出 0, 0.2, 0.4, 0.6, 0.8, 1.0
end
常见问题:
• 浮点精度问题:
for i = 0, 0.1, 0.1 do print(i) end -- 可能因精度丢失导致死循环
解决:改用整数步长后缩放:
for i = 0, 1, 0.1 do ... end -- 改为整数逻辑
2. 泛型 for
循环
基础语法:
-- 格式:for k, v in pairs(t) do ... end
local t = {
a=1, b=2, c=3}
for key, value in pairs(t) do
print(key, value) -- 遍历表的所有键值对
end
for index, value in ipairs({
"a", "b", "c"}) do
print(index, value) -- 遍历数组部分(1-based)
end
关键特性:
• 迭代器协议:pairs
(遍历所有键值)和 ipairs
(遍历数组部分)是内置迭代器。
• 自定义迭代器:
-- 生成斐波那契数列的迭代器
function fib()
local a, b = 0, 1
return function()
a, b = b, a + b
return a
end
end
for num in fib() do
if num > 100 then break end
print(num)
end
二、while
循环
基础语法:
-- 格式:while condition do ... end
local i = 1
while i <= 5 do
print(i)
i = i + 1 -- 必须修改条件相关变量,否则死循环
end
关键特性:
• 条件前置:每次循环开始前检查条件。
• 无限循环:
while true do
-- 需要主动 break 或 return 退出
end
三、进阶用法
1. 嵌套循环与标签控制
::outer_loop::
for i = 1, 3 do
for j = 1, 3 do
if i == 2 and j == 2 then
goto outer_loop -- 跳出外层循环
end
print("i:", i, "j:", j)
end
end
2. 循环控制命令
• break
:立即退出当前最内层循环。
• continue
:跳过当前迭代(Lua 5.3+ 支持):
for i = 1, 5 do
if i == 3 then continue end
if i == 5 then break end
print("Current value:", i)
end
-- 输出:1,2,4
3. 性能优化技巧
• 减少循环内计算:
-- 不推荐:每次循环都计算 len
for i = 1, #table do
local len = #table -- 重复计算
print(i, len)
end
-- 推荐:预计算
local len = #table
for i = 1, len do
print(i, len)
end
• 使用泛型 for
替代手动索引:
-- 低效写法
local i = 1
while my_table[i] do
print(my_table[i])
i = i + 1
end
-- 高效写法
for _, value in ipairs(my_table) do
print(value)
end
四、特殊场景与模式
1. 遍历复杂数据结构
-- 遍历嵌套表(深度优先)
local function deep_traverse(t)
for k, v in pairs(t) do
if type(v) == "table" then
deep_traverse(v)
else
print(k, v)
end
end
end
2. 模拟 C 风格 for
循环
-- 自定义范围迭代器
function range(start, stop, step)
step = step or 1
local current = start
return function()
if (step > 0 and current <= stop) or (step < 0 and current >= stop) then
local value = current
current = current + step
return value
end
end
end
for i in range(1, 5, 1) do print(i) end -- 1,2,3,4,5
3. 事件循环与协程
-- 使用协程实现非阻塞循环
local function task()
for i = 1, 5 do
print("Coroutine:", i)
coroutine.yield() -- 主动让出执行权
end
end
local co = coroutine.create(task)
coroutine.resume(co) -- 启动协程
coroutine.resume(co) -- 恢复执行
五、注意事项与最佳实践
1. 避免死循环
• 确保循环条件最终会变为 false
:
-- 错误示例:缺少变量递增
local i = 1
while i <= 5 do
print(i)
-- i 未更新 → 死循环
end
2. 变量作用域
• for
循环变量是块级作用域(Lua 5.3+):
for i = 1, 3 do
local i = "inner" -- 局部变量,不影响外层循环
print(i) -- 输出 "inner"
end
3. 性能对比
场景 | 推荐结构 | 原因 |
---|---|---|
遍历数组 | ipairs |
效率高,自动处理 nil |
遍历字典 | pairs |
遍历所有键值对 |
已知迭代次数 | 数值 for |
更直观 |
条件不确定的重复执行 | while /repeat |
灵活控制退出条件 |
六、实战示例
示例1:猜数字游戏
math.randomseed(os.time())
local secret = math.random(1, 100)
print("猜一个 1~100 的数字:")
while true do
local guess = tonumber(io.read())
if not guess then break end -- 输入非数字退出
if guess < secret then
print("太小了!")
elseif guess > secret then
print("太大了!")
else
print("恭喜猜中!")
break
end
end
示例2:批量文件处理
local files = {
"a.txt", "b.txt", "c.txt"}
for _, filename in ipairs(files) do
local file = io.open(filename, "r")
if file then
print("处理文件:", filename)
file:close()
else
print("文件不存在:", filename)
end
end
示例3:生产者-消费者模型
local queue = {
}
local function producer()
for i = 1, 5 do
table.insert(queue, "item"..i)
print("生产:", i)
end
end
local function consumer()
while true do
if #queue > 0 then
local item = table.remove(queue, 1)
print("消费:", item)
else
break
end
end
end
producer()
consumer()
通过灵活组合 for
和 while
循环,并结合 Lua 的迭代器和协程特性,可以实现高效且易读的逻辑控制。对于复杂场景,建议优先使用泛型 for
和表驱动模式,减少手动循环控制带来的复杂性。