Skip to content

Lua流程控制

概述

流程控制是编程语言的核心特性,Lua提供了条件语句、循环语句和跳转语句来控制程序的执行流程。

1. 条件语句

1.1 if语句

最基本的条件语句,用于根据条件执行不同的代码块。

lua
-- 基本if语句
local score = 85

if score >= 60 then
    print("及格")
end

-- if-else语句
local age = 18

if age >= 18 then
    print("成年人")
else
    print("未成年人")
end

-- if-elseif-else语句
local grade = 85

if grade >= 90 then
    print("优秀")
elseif grade >= 80 then
    print("良好")
elseif grade >= 70 then
    print("中等")
elseif grade >= 60 then
    print("及格")
else
    print("不及格")
end

1.2 条件表达式

在Lua中,只有nilfalse被认为是假值,其他所有值都是真值。

lua
-- 数字0是真值
if 0 then
    print("0是真值")  -- 会执行
end

-- 空字符串是真值
if "" then
    print("空字符串是真值")  -- 会执行
end

-- 空表是真值
if {} then
    print("空表是真值")  -- 会执行
end

-- nil和false是假值
if nil then
    print("这不会执行")
end

if false then
    print("这也不会执行")
end

1.3 复杂条件

lua
local username = "admin"
local password = "123456"
local is_active = true

-- 使用逻辑运算符组合条件
if username == "admin" and password == "123456" and is_active then
    print("登录成功")
elseif not is_active then
    print("账户已被禁用")
else
    print("用户名或密码错误")
end

-- 使用括号明确优先级
local a, b, c = 10, 20, 30
if (a > b) or (b > c and a > c) then
    print("复杂条件满足")
end

2. 循环语句

2.1 while循环

当条件为真时重复执行代码块。

lua
-- 基本while循环
local i = 1
while i <= 5 do
    print("第" .. i .. "次循环")
    i = i + 1
end

-- 无限循环(需要break跳出)
local count = 0
while true do
    count = count + 1
    print("计数:", count)
    
    if count >= 3 then
        break  -- 跳出循环
    end
end

-- 条件循环
local input = ""
while input ~= "quit" do
    print("请输入命令 (输入quit退出):")
    -- input = io.read()  -- 实际应用中读取用户输入
    input = "quit"  -- 示例中直接设置退出条件
end

2.2 repeat-until循环

至少执行一次,然后检查条件。

lua
-- 基本repeat-until循环
local num = 1
repeat
    print("数字:", num)
    num = num + 1
until num > 5

-- 菜单循环示例
local choice
repeat
    print("1. 选项一")
    print("2. 选项二")
    print("3. 退出")
    print("请选择:")
    
    -- choice = tonumber(io.read())  -- 实际应用中读取用户输入
    choice = 3  -- 示例中直接设置退出条件
    
    if choice == 1 then
        print("执行选项一")
    elseif choice == 2 then
        print("执行选项二")
    elseif choice == 3 then
        print("退出程序")
    else
        print("无效选择")
    end
until choice == 3

2.3 for循环

数值for循环

lua
-- 基本数值for循环
for i = 1, 5 do
    print("i =", i)
end
-- 输出: 1, 2, 3, 4, 5

-- 指定步长
for i = 1, 10, 2 do
    print("奇数:", i)
end
-- 输出: 1, 3, 5, 7, 9

-- 递减循环
for i = 5, 1, -1 do
    print("倒计时:", i)
end
-- 输出: 5, 4, 3, 2, 1

-- 浮点数循环
for i = 0, 1, 0.1 do
    print(string.format("%.1f", i))
end

泛型for循环

lua
-- 遍历数组
local fruits = {"apple", "banana", "orange", "grape"}

-- 使用ipairs遍历数组(推荐)
for index, value in ipairs(fruits) do
    print(index, value)
end

-- 遍历表的所有键值对
local person = {
    name = "Alice",
    age = 30,
    city = "Beijing"
}

-- 使用pairs遍历所有键值对
for key, value in pairs(person) do
    print(key, value)
end

-- 遍历字符串的每一行
local text = "第一行\n第二行\n第三行"
for line in string.gmatch(text, "[^\n]+") do
    print("行内容:", line)
end

2.4 嵌套循环

lua
-- 九九乘法表
for i = 1, 9 do
    for j = 1, i do
        io.write(j .. "x" .. i .. "=" .. (i*j) .. "\t")
    end
    print()  -- 换行
end

-- 二维数组遍历
local matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
}

for i = 1, #matrix do
    for j = 1, #matrix[i] do
        io.write(matrix[i][j] .. " ")
    end
    print()
end

3. 跳转语句

3.1 break语句

用于跳出当前循环。

lua
-- 在while循环中使用break
local i = 1
while true do
    if i > 5 then
        break  -- 跳出循环
    end
    print("i =", i)
    i = i + 1
end

-- 在for循环中使用break
for i = 1, 10 do
    if i == 6 then
        break  -- 当i等于6时跳出循环
    end
    print(i)
end
-- 输出: 1, 2, 3, 4, 5

-- 在嵌套循环中,break只跳出最内层循环
for i = 1, 3 do
    print("外层循环:", i)
    for j = 1, 5 do
        if j == 3 then
            break  -- 只跳出内层循环
        end
        print("  内层循环:", j)
    end
end

3.2 goto语句(Lua 5.2+)

用于无条件跳转到标签位置。

lua
-- 基本goto用法
local x = 10

if x > 5 then
    goto skip_block
end

print("这行不会执行")

::skip_block::
print("跳转到这里")

-- 使用goto跳出嵌套循环
for i = 1, 5 do
    for j = 1, 5 do
        if i * j > 10 then
            goto exit_loops  -- 跳出所有循环
        end
        print(i, j, i * j)
    end
end

::exit_loops::
print("跳出嵌套循环")

-- goto的限制示例
local function demo_goto_limits()
    local x = 1
    
    if x == 1 then
        -- goto cannot_reach  -- 错误:不能跳转到不同的块
    end
    
    do
        ::cannot_reach::
        print("这是一个标签")
    end
end

4. 实际应用示例

4.1 输入验证

lua
local function get_valid_number(prompt, min, max)
    local num
    repeat
        print(prompt)
        -- num = tonumber(io.read())  -- 实际应用中读取输入
        num = 50  -- 示例值
        
        if not num then
            print("请输入一个有效的数字")
        elseif num < min or num > max then
            print(string.format("数字必须在%d到%d之间", min, max))
        end
    until num and num >= min and num <= max
    
    return num
end

-- 使用示例
-- local age = get_valid_number("请输入年龄 (1-120):", 1, 120)

4.2 菜单系统

lua
local function show_menu()
    local menu_items = {
        "1. 新建文件",
        "2. 打开文件",
        "3. 保存文件",
        "4. 退出程序"
    }
    
    for _, item in ipairs(menu_items) do
        print(item)
    end
end

local function handle_menu()
    local choice
    repeat
        show_menu()
        print("请选择操作:")
        
        -- choice = tonumber(io.read())  -- 实际应用中读取输入
        choice = 4  -- 示例中直接退出
        
        if choice == 1 then
            print("新建文件...")
        elseif choice == 2 then
            print("打开文件...")
        elseif choice == 3 then
            print("保存文件...")
        elseif choice == 4 then
            print("退出程序")
        else
            print("无效选择,请重新输入")
        end
    until choice == 4
end

-- handle_menu()

4.3 数据处理

lua
-- 统计数组中的正数、负数和零的个数
local function count_numbers(numbers)
    local positive, negative, zero = 0, 0, 0
    
    for _, num in ipairs(numbers) do
        if num > 0 then
            positive = positive + 1
        elseif num < 0 then
            negative = negative + 1
        else
            zero = zero + 1
        end
    end
    
    return positive, negative, zero
end

local data = {1, -2, 0, 5, -3, 0, 7, -1}
local pos, neg, zero = count_numbers(data)
print(string.format("正数: %d, 负数: %d, 零: %d", pos, neg, zero))

4.4 查找算法

lua
-- 线性查找
local function linear_search(array, target)
    for i, value in ipairs(array) do
        if value == target then
            return i  -- 返回索引
        end
    end
    return nil  -- 未找到
end

-- 二分查找(假设数组已排序)
local function binary_search(array, target)
    local left, right = 1, #array
    
    while left <= right do
        local mid = math.floor((left + right) / 2)
        
        if array[mid] == target then
            return mid
        elseif array[mid] < target then
            left = mid + 1
        else
            right = mid - 1
        end
    end
    
    return nil  -- 未找到
end

-- 测试查找算法
local sorted_array = {1, 3, 5, 7, 9, 11, 13, 15}
local target = 7

local linear_result = linear_search(sorted_array, target)
local binary_result = binary_search(sorted_array, target)

print("线性查找结果:", linear_result)  -- 4
print("二分查找结果:", binary_result)  -- 4

5. 性能优化技巧

5.1 循环优化

lua
-- 避免在循环中重复计算
local array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

-- 不好的做法
for i = 1, #array do  -- 每次都计算#array
    print(array[i])
end

-- 好的做法
local len = #array
for i = 1, len do
    print(array[i])
end

-- 或者使用ipairs
for i, v in ipairs(array) do
    print(v)
end

5.2 条件优化

lua
-- 将最可能的条件放在前面
local function process_grade(grade)
    -- 假设大部分学生都是及格的
    if grade >= 60 and grade < 70 then
        return "及格"
    elseif grade >= 70 and grade < 80 then
        return "中等"
    elseif grade >= 80 and grade < 90 then
        return "良好"
    elseif grade >= 90 then
        return "优秀"
    else
        return "不及格"
    end
end

6. 常见陷阱和注意事项

6.1 循环变量作用域

lua
-- 循环变量的作用域仅在循环内
for i = 1, 3 do
    print(i)
end
-- print(i)  -- 错误:i在此处不可访问

-- 如果需要在循环外使用,需要预先声明
local i
for i = 1, 3 do
    print(i)
end
print("最后的i值:", i)  -- 3

6.2 浮点数循环

lua
-- 浮点数精度问题
for i = 0, 1, 0.1 do
    print(i)
end
-- 可能不会精确输出0.1, 0.2, 0.3...

-- 更好的做法
for i = 0, 10 do
    local val = i / 10
    print(val)
end

6.3 修改正在遍历的表

lua
local t = {1, 2, 3, 4, 5}

-- 危险:在遍历时修改表
for i, v in ipairs(t) do
    if v % 2 == 0 then
        table.remove(t, i)  -- 可能导致跳过元素
    end
end

-- 安全的做法:反向遍历
for i = #t, 1, -1 do
    if t[i] % 2 == 0 then
        table.remove(t, i)
    end
end

总结

Lua的流程控制语句简洁而强大:

  1. 条件语句if-then-else支持复杂的条件判断
  2. 循环语句whilerepeat-untilfor满足不同的循环需求
  3. 跳转语句breakgoto提供灵活的控制流
  4. 泛型for循环:配合迭代器实现强大的遍历功能

掌握这些控制结构是编写高效Lua程序的基础,合理使用它们可以让代码更加清晰和高效。

基于 MIT 许可发布