在 Lua 中,for
和 while
是兩種核心的循環結構,用于實現重復執行邏輯。以下是它們的詳細用法、進階技巧及注意事項:
在 Lua 中,`for` 和 `while` 是兩種核心的循環結構的詳細用法—目錄
- 一、`for` 循環
- 1. 數值 `for` 循環
- 基礎語法:
- 關鍵特性:
- 常見問題:
- 2. 泛型 `for` 循環
- 基礎語法:
- 關鍵特性:
- 二、`while` 循環
- 基礎語法:
- 關鍵特性:
- 三、進階用法
- 1. 嵌套循環與標簽控制
- 2. 循環控制命令
- 3. 性能優化技巧
- 四、特殊場景與模式
- 1. 遍歷復雜數據結構
- 2. 模擬 C 風格 `for` 循環
- 3. 事件循環與協程
- 五、注意事項與最佳實踐
- 1. 避免死循環
- 2. 變量作用域
- 3. 性能對比
- 六、實戰示例
- 示例1:猜數字游戲
- 示例2:批量文件處理
- 示例3:生產者-消費者模型
一、for
循環
1. 數值 for
循環
基礎語法:
-- 格式:for var = start, end [, step] do ... end
for i = 1, 5 doprint(i) -- 輸出 1 到 5
endfor i = 10, 1, -2 doprint(i) -- 輸出 10,8,6,4,2
end
關鍵特性:
? 范圍表達式:start
、end
和 step
均為表達式,運行時計算。
? 隱式步長:默認步長為 1
。
? 浮點數支持:
for i = 0, 1, 0.2 doprint(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) doprint(key, value) -- 遍歷表的所有鍵值對
endfor index, value in ipairs({"a", "b", "c"}) doprint(index, value) -- 遍歷數組部分(1-based)
end
關鍵特性:
? 迭代器協議:pairs
(遍歷所有鍵值)和 ipairs
(遍歷數組部分)是內置迭代器。
? 自定義迭代器:
-- 生成斐波那契數列的迭代器
function fib()local a, b = 0, 1return function()a, b = b, a + breturn aend
endfor num in fib() doif num > 100 then break endprint(num)
end
二、while
循環
基礎語法:
-- 格式:while condition do ... end
local i = 1
while i <= 5 doprint(i)i = i + 1 -- 必須修改條件相關變量,否則死循環
end
關鍵特性:
? 條件前置:每次循環開始前檢查條件。
? 無限循環:
while true do-- 需要主動 break 或 return 退出
end
三、進階用法
1. 嵌套循環與標簽控制
::outer_loop::
for i = 1, 3 dofor j = 1, 3 doif i == 2 and j == 2 thengoto outer_loop -- 跳出外層循環endprint("i:", i, "j:", j)end
end
2. 循環控制命令
? break
:立即退出當前最內層循環。
? continue
:跳過當前迭代(Lua 5.3+ 支持):
for i = 1, 5 doif i == 3 then continue endif i == 5 then break endprint("Current value:", i)
end
-- 輸出:1,2,4
3. 性能優化技巧
? 減少循環內計算:
-- 不推薦:每次循環都計算 len
for i = 1, #table dolocal len = #table -- 重復計算print(i, len)
end-- 推薦:預計算
local len = #table
for i = 1, len doprint(i, len)
end
? 使用泛型 for
替代手動索引:
-- 低效寫法
local i = 1
while my_table[i] doprint(my_table[i])i = i + 1
end-- 高效寫法
for _, value in ipairs(my_table) doprint(value)
end
四、特殊場景與模式
1. 遍歷復雜數據結構
-- 遍歷嵌套表(深度優先)
local function deep_traverse(t)for k, v in pairs(t) doif type(v) == "table" thendeep_traverse(v)elseprint(k, v)endend
end
2. 模擬 C 風格 for
循環
-- 自定義范圍迭代器
function range(start, stop, step)step = step or 1local current = startreturn function()if (step > 0 and current <= stop) or (step < 0 and current >= stop) thenlocal value = currentcurrent = current + stepreturn valueendend
endfor i in range(1, 5, 1) do print(i) end -- 1,2,3,4,5
3. 事件循環與協程
-- 使用協程實現非阻塞循環
local function task()for i = 1, 5 doprint("Coroutine:", i)coroutine.yield() -- 主動讓出執行權end
endlocal co = coroutine.create(task)
coroutine.resume(co) -- 啟動協程
coroutine.resume(co) -- 恢復執行
五、注意事項與最佳實踐
1. 避免死循環
? 確保循環條件最終會變為 false
:
-- 錯誤示例:缺少變量遞增
local i = 1
while i <= 5 doprint(i)-- i 未更新 → 死循環
end
2. 變量作用域
? for
循環變量是塊級作用域(Lua 5.3+):
for i = 1, 3 dolocal 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 dolocal guess = tonumber(io.read())if not guess then break end -- 輸入非數字退出if guess < secret thenprint("太小了!")elseif guess > secret thenprint("太大了!")elseprint("恭喜猜中!")breakend
end
示例2:批量文件處理
local files = {"a.txt", "b.txt", "c.txt"}
for _, filename in ipairs(files) dolocal file = io.open(filename, "r")if file thenprint("處理文件:", filename)file:close()elseprint("文件不存在:", filename)end
end
示例3:生產者-消費者模型
local queue = {}
local function producer()for i = 1, 5 dotable.insert(queue, "item"..i)print("生產:", i)end
endlocal function consumer()while true doif #queue > 0 thenlocal item = table.remove(queue, 1)print("消費:", item)elsebreakendend
endproducer()
consumer()
通過靈活組合 for
和 while
循環,并結合 Lua 的迭代器和協程特性,可以實現高效且易讀的邏輯控制。對于復雜場景,建議優先使用泛型 for
和表驅動模式,減少手動循環控制帶來的復雜性。