引言

嵌套循环是处理多维数据、矩阵运算、组合问题等复杂场景的重要工具。在Rust中,你可以将任何类型的循环(loop、while、for)相互嵌套,形成多层次的控制流结构。

本文将深入探讨Rust嵌套循环的所有方面,包括:

  • 嵌套循环的基本概念和语法
  • 不同类型循环的组合嵌套
  • 循环标签(Loop Labels)的高级用法
  • 嵌套循环中的break和continue控制
  • 二维和多维数据的处理
  • 常见算法模式(矩阵运算、搜索、排列组合)
  • 性能优化和最佳实践
  • 实际项目应用案例

通过本文的学习,你将能够:

  • 熟练使用嵌套循环解决复杂问题
  • 掌握循环标签控制嵌套循环的技巧
  • 理解嵌套循环的性能特点
  • 编写高效且可读的嵌套循环代码

1. 嵌套循环基础

1.1 什么是嵌套循环?

嵌套循环是指在一个循环的内部包含另一个或多个循环的结构:

fn main() {
    // 外层循环
    for i in 1..=3 {
        // 内层循环
        for j in 1..=3 {
            println!("i={}, j={}", i, j);
        }
    }
}

输出

在这里插入图片描述

1.2 嵌套深度

Rust支持任意深度的嵌套,但要注意可读性:

fn main() {
    // 两层嵌套
    for i in 1..=2 {
        for j in 1..=2 {
            println!("外层: {}, 内层: {}", i, j);
        }
    }
    
    // 三层嵌套
    for i in 1..=2 {
        for j in 1..=2 {
            for k in 1..=2 {
                println!("i={}, j={}, k={}", i, j, k);
            }
        }
    }
}

在这里插入图片描述

1.3 嵌套循环的执行顺序

理解嵌套循环的执行顺序至关重要:

fn main() {
    for i in 1..=2 {
        println!("外层循环开始: i={}", i);
        
        for j in 1..=2 {
            println!("  内层循环: i={}, j={}", i, j);
        }
        
        println!("外层循环结束: i={}", i);
    }
}

在这里插入图片描述

执行流程

  1. 外层循环第一次迭代(i=1)
  2. 内层循环完整执行(j=1, j=2)
  3. 外层循环第二次迭代(i=2)
  4. 内层循环再次完整执行(j=1, j=2)

2. 不同类型循环的嵌套组合

2.1 for嵌套for

最常见的嵌套模式,用于遍历二维结构:

fn main() {
    // 遍历二维数组
    let matrix = [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
    ];
    
    for row in matrix.iter() {
        for &element in row.iter() {
            print!("{} ", element);
        }
        println!();
    }
}

在这里插入图片描述

2.2 while嵌套while

基于条件的双重判断:

fn main() {
    let mut i = 1;
    while i <= 3 {
        let mut j = 1;
        while j <= 3 {
            println!("i={}, j={}", i, j);
            j += 1;
        }
        i += 1;
    }
}

2.3 for嵌套while

结合遍历和条件判断:

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    
    for &num in numbers.iter() {
        let mut counter = 0;
        while counter < num {
            print!("*");
            counter += 1;
        }
        println!();
    }
}

2.4 while嵌套for

fn main() {
    let mut row = 0;
    while row < 3 {
        for col in 1..=3 {
            print!("({},{}) ", row, col);
        }
        println!();
        row += 1;
    }
}

2.5 loop嵌套组合

fn main() {
    let mut outer_count = 0;
    
    'outer: loop {
        outer_count += 1;
        
        for inner in 1..=3 {
            if outer_count >= 2 && inner == 2 {
                break 'outer;  // 退出外层循环
            }
            println!("外层: {}, 内层: {}", outer_count, inner);
        }
    }
}

3. 循环标签深入使用

3.1 为什么需要循环标签?

嵌套循环中,默认的breakcontinue只影响最内层循环。要控制外层循环,需要使用标签:

fn main() {
    // 没有标签:只能退出内层循环
    for i in 1..=3 {
        for j in 1..=3 {
            if j == 2 {
                break;  // 只退出内层循环
            }
            println!("i={}, j={}", i, j);
        }
    }
    // 输出: (1,1), (2,1), (3,1)
    
    println!();
    
    // 使用标签:可以退出外层循环
    'outer: for i in 1..=3 {
        'inner: for j in 1..=3 {
            if j == 2 {
                break 'outer;  // 退出外层循环
            }
            println!("i={}, j={}", i, j);
        }
    }
    // 输出: (1,1) 然后退出
}

3.2 标签命名规范

循环标签遵循标识符命名规则:

fn main() {
    // 使用有意义的标签名
    'search: for i in 1..=5 {
        'find: for j in 1..=5 {
            if i * j == 12 {
                println!("找到: {} * {} = {}", i, j, i * j);
                break 'search;  // 找到后退出所有循环
            }
        }
    }
}

3.3 continue与标签配合

fn main() {
    'outer: for i in 1..=3 {
        println!("外层循环: i={}", i);
        
        'inner: for j in 1..=5 {
            if j == 3 {
                continue 'outer;  // 继续外层循环的下一次迭代
            }
            println!("  内层: j={}", j);
        }
    }
    // 当j==3时,跳过内层循环剩余部分,直接进行外层下一次迭代
}

3.4 多层嵌套中的标签

fn main() {
    'level1: for i in 1..=2 {
        'level2: for j in 1..=2 {
            'level3: for k in 1..=2 {
                if k == 2 {
                    break 'level1;  // 直接退出最外层
                }
                println!("i={}, j={}, k={}", i, j, k);
            }
        }
    }
}

4. 嵌套循环中的控制流

4.1 break在不同嵌套层级

fn main() {
    // 示例:在二维数组中查找目标值
    let matrix = [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
    ];
    let target = 5;
    
    'search: for (i, row) in matrix.iter().enumerate() {
        for (j, &value) in row.iter().enumerate() {
            if value == target {
                println!("找到 {} 在位置 ({}, {})", target, i, j);
                break 'search;  // 找到后退出所有循环
            }
        }
    }
}

4.2 continue在不同嵌套层级

fn main() {
    // 示例:跳过某些行和列的打印
    for i in 1..=5 {
        if i == 3 {
            continue;  // 跳过外层循环的第三次迭代
        }
        
        for j in 1..=5 {
            if j == 3 {
                continue;  // 跳过内层循环的第三次迭代
            }
            print!("({},{}) ", i, j);
        }
        println!();
    }
    
    println!();
    
    // 使用标签控制外层continue
    'outer: for i in 1..=5 {
        for j in 1..=5 {
            if j == 3 {
                continue 'outer;  // 跳过内层剩余,继续外层下一次
            }
            print!("({},{}) ", i, j);
        }
        println!();
    }
}

4.3 条件跳转模式

fn main() {
    // 模式:找到第一个满足条件的组合后退出
    let mut found = false;
    
    'outer: for i in 1..=10 {
        for j in 1..=10 {
            if i * j == 24 {
                println!("{} * {} = 24", i, j);
                found = true;
                break 'outer;
            }
        }
    }
    
    if !found {
        println!("未找到");
    }
}

5. 二维数据的处理

5.1 矩阵遍历

fn main() {
    // 创建一个3x3矩阵
    let mut matrix = vec![
        vec![1, 2, 3],
        vec![4, 5, 6],
        vec![7, 8, 9],
    ];
    
    // 按行遍历
    println!("按行遍历:");
    for (i, row) in matrix.iter().enumerate() {
        for (j, &val) in row.iter().enumerate() {
            print!("matrix[{}][{}]={} ", i, j, val);
        }
        println!();
    }
    
    // 按列遍历
    println!("\n按列遍历:");
    for col in 0..3 {
        for row in 0..3 {
            print!("matrix[{}][{}]={} ", row, col, matrix[row][col]);
        }
        println!();
    }
}

5.2 矩阵运算

fn main() {
    // 矩阵加法
    let a = [
        [1, 2, 3],
        [4, 5, 6],
    ];
    
    let b = [
        [7, 8, 9],
        [10, 11, 12],
    ];
    
    let mut result = [[0; 3]; 2];
    
    for i in 0..2 {
        for j in 0..3 {
            result[i][j] = a[i][j] + b[i][j];
        }
    }
    
    println!("矩阵加法结果:");
    for row in result.iter() {
        println!("{:?}", row);
    }
    
    // 矩阵乘法
    let m1 = [
        [1, 2],
        [3, 4],
    ];
    
    let m2 = [
        [5, 6],
        [7, 8],
    ];
    
    let mut product = [[0; 2]; 2];
    
    for i in 0..2 {
        for j in 0..2 {
            for k in 0..2 {
                product[i][j] += m1[i][k] * m2[k][j];
            }
        }
    }
    
    println!("\n矩阵乘法结果:");
    for row in product.iter() {
        println!("{:?}", row);
    }
}

5.3 矩阵转置

fn main() {
    let matrix = [
        [1, 2, 3],
        [4, 5, 6],
    ];
    
    let mut transposed = [[0; 2]; 3];
    
    for i in 0..2 {
        for j in 0..3 {
            transposed[j][i] = matrix[i][j];
        }
    }
    
    println!("原矩阵:");
    for row in matrix.iter() {
        println!("{:?}", row);
    }
    
    println!("\n转置矩阵:");
    for row in transposed.iter() {
        println!("{:?}", row);
    }
}

6. 图形和图案打印

6.1 打印各种图案

fn main() {
    // 直角三角形
    println!("直角三角形:");
    let n = 5;
    for i in 1..=n {
        for _ in 1..=i {
            print!("*");
        }
        println!();
    }
    
    // 倒直角三角形
    println!("\n倒直角三角形:");
    for i in (1..=n).rev() {
        for _ in 1..=i {
            print!("*");
        }
        println!();
    }
    
    // 等腰三角形
    println!("\n等腰三角形:");
    for i in 1..=n {
        // 打印空格
        for _ in 0..(n - i) {
            print!(" ");
        }
        // 打印星号
        for _ in 1..=(2 * i - 1) {
            print!("*");
        }
        println!();
    }
    
    // 菱形
    println!("\n菱形:");
    // 上半部分
    for i in 1..=n {
        for _ in 0..(n - i) {
            print!(" ");
        }
        for _ in 1..=(2 * i - 1) {
            print!("*");
        }
        println!();
    }
    // 下半部分
    for i in (1..n).rev() {
        for _ in 0..(n - i) {
            print!(" ");
        }
        for _ in 1..=(2 * i - 1) {
            print!("*");
        }
        println!();
    }
}

6.2 数字图案

fn main() {
    // 数字金字塔
    println!("数字金字塔:");
    let n = 5;
    for i in 1..=n {
        // 打印空格
        for _ in 0..(n - i) {
            print!(" ");
        }
        // 打印递增数字
        for j in 1..=i {
            print!("{} ", j);
        }
        println!();
    }
    
    // 乘法表
    println!("\n九九乘法表:");
    for i in 1..=9 {
        for j in 1..=i {
            print!("{}×{}={}\t", j, i, i * j);
        }
        println!();
    }
}

在这里插入图片描述

7. 搜索算法

7.1 二维数组搜索

fn main() {
    let matrix = vec![
        vec![1, 4, 7, 11],
        vec![2, 5, 8, 12],
        vec![3, 6, 9, 16],
        vec![10, 13, 14, 17],
    ];
    
    let target = 5;
    let mut found = false;
    let mut position = None;
    
    'search: for (i, row) in matrix.iter().enumerate() {
        for (j, &value) in row.iter().enumerate() {
            if value == target {
                position = Some((i, j));
                found = true;
                break 'search;
            }
        }
    }
    
    match position {
        Some((i, j)) => println!("找到 {} 在位置 ({}, {})", target, i, j),
        None => println!("未找到 {}", target),
    }
}

7.2 查找所有匹配项

fn main() {
    let matrix = vec![
        vec![1, 2, 3, 2],
        vec![4, 2, 6, 2],
        vec![7, 8, 2, 9],
    ];
    
    let target = 2;
    let mut positions = Vec::new();
    
    for (i, row) in matrix.iter().enumerate() {
        for (j, &value) in row.iter().enumerate() {
            if value == target {
                positions.push((i, j));
            }
        }
    }
    
    println!("找到 {} 出现在以下位置:", target);
    for (i, j) in positions {
        println!("  ({}, {})", i, j);
    }
}

7.3 条件搜索

fn main() {
    let numbers = vec![
        vec![1, 4, 7],
        vec![2, 5, 8],
        vec![3, 6, 9],
    ];
    
    // 查找第一个大于5的数和位置
    let mut result = None;
    
    'search: for (i, row) in numbers.iter().enumerate() {
        for (j, &num) in row.iter().enumerate() {
            if num > 5 {
                result = Some((i, j, num));
                break 'search;
            }
        }
    }
    
    match result {
        Some((i, j, val)) => println!("找到: {} 在位置 ({}, {})", val, i, j),
        None => println!("未找到大于5的数"),
    }
}

8. 排列组合问题

8.1 生成所有组合

fn main() {
    // 从三个数中选两个的所有组合
    let numbers = [1, 2, 3];
    
    println!("所有两两组合:");
    for i in 0..numbers.len() {
        for j in (i + 1)..numbers.len() {
            println!("({}, {})", numbers[i], numbers[j]);
        }
    }
    
    // 三元组组合
    println!("\n所有三元组组合:");
    let items = ['A', 'B', 'C', 'D'];
    for i in 0..items.len() {
        for j in (i + 1)..items.len() {
            for k in (j + 1)..items.len() {
                println!("({}, {}, {})", items[i], items[j], items[k]);
            }
        }
    }
}

8.2 排列问题

fn main() {
    // 打印所有可能的两位数组合(允许重复)
    println!("所有可能的两位数(允许重复):");
    for i in 1..=3 {
        for j in 1..=3 {
            println!("{}{}", i, j);
        }
    }
    
    // 打印所有可能的两位数组合(不允许重复)
    println!("\n所有可能的两位数(不允许重复):");
    for i in 1..=3 {
        for j in 1..=3 {
            if i != j {
                println!("{}{}", i, j);
            }
        }
    }
}

9. 实际项目应用

9.1 棋盘游戏逻辑

fn main() {
    // 模拟井字棋棋盘检查
    let board = [
        ['X', 'O', 'X'],
        ['O', 'X', 'O'],
        ['X', 'O', 'X'],
    ];
    
    // 检查行
    fn check_rows(board: &[[char; 3]; 3]) -> Option<char> {
        for row in board.iter() {
            if row[0] == row[1] && row[1] == row[2] && row[0] != ' ' {
                return Some(row[0]);
            }
        }
        None
    }
    
    // 检查列
    fn check_cols(board: &[[char; 3]; 3]) -> Option<char> {
        for col in 0..3 {
            if board[0][col] == board[1][col] 
            && board[1][col] == board[2][col] 
            && board[0][col] != ' ' {
                return Some(board[0][col]);
            }
        }
        None
    }
    
    match check_rows(&board) {
        Some(winner) => println!("行胜利: {}", winner),
        None => println!("行无胜利者"),
    }
    
    match check_cols(&board) {
        Some(winner) => println!("列胜利: {}", winner),
        None => println!("列无胜利者"),
    }
}

9.2 图像处理操作

fn main() {
    // 模拟图像翻转(2D数组操作)
    let mut image = vec![
        vec![1, 2, 3],
        vec![4, 5, 6],
        vec![7, 8, 9],
    ];
    
    let rows = image.len();
    let cols = image[0].len();
    
    // 水平翻转
    for i in 0..rows {
        for j in 0..cols / 2 {
            let temp = image[i][j];
            image[i][j] = image[i][cols - 1 - j];
            image[i][cols - 1 - j] = temp;
        }
    }
    
    println!("水平翻转后:");
    for row in image.iter() {
        println!("{:?}", row);
    }
}

9.3 动态规划表填充

fn main() {
    // 斐波那契数列的动态规划表
    let n = 10;
    let mut dp = vec![0; n + 1];
    dp[1] = 1;
    
    for i in 2..=n {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    
    println!("斐波那契数列(动态规划):");
    for (i, &val) in dp.iter().enumerate().skip(1) {
        print!("{} ", val);
    }
    println!();
    
    // 二维DP:最长公共子序列表
    let s1 = "ABCDGH";
    let s2 = "AEDFHR";
    let m = s1.len();
    let n = s2.len();
    
    let mut dp = vec![vec![0; n + 1]; m + 1];
    
    for i in 1..=m {
        for j in 1..=n {
            if s1.chars().nth(i - 1) == s2.chars().nth(j - 1) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = dp[i - 1][j].max(dp[i][j - 1]);
            }
        }
    }
    
    println!("最长公共子序列长度: {}", dp[m][n]);
}

10. 性能优化技巧

10.1 减少嵌套深度

fn main() {
    // ❌ 不推荐:三层嵌套
    // for i in 0..100 {
    //     for j in 0..100 {
    //         for k in 0..100 {
    //             // 操作
    //         }
    //     }
    // }
    
    // ✅ 推荐:提取内层逻辑到函数
    fn process_inner(j: usize, k: usize) {
        // 内层逻辑
    }
    
    for i in 0..100 {
        for j in 0..100 {
            for k in 0..100 {
                process_inner(j, k);
            }
        }
    }
}

10.2 提前退出优化

fn main() {
    // 在搜索中使用break提前退出
    let matrix = vec![
        vec![1, 2, 3],
        vec![4, 5, 6],
        vec![7, 8, 9],
    ];
    
    let target = 5;
    
    // 使用标签提前退出
    'search: for (i, row) in matrix.iter().enumerate() {
        for (j, &val) in row.iter().enumerate() {
            if val == target {
                println!("找到!位置: ({}, {})", i, j);
                break 'search;  // 找到后立即退出
            }
        }
    }
}

10.3 使用迭代器替代嵌套循环

fn main() {
    let matrix = vec![
        vec![1, 2, 3],
        vec![4, 5, 6],
        vec![7, 8, 9],
    ];
    
    // 方式1:嵌套for循环
    let mut sum = 0;
    for row in &matrix {
        for &val in row {
            sum += val;
        }
    }
    println!("嵌套循环求和: {}", sum);
    
    // 方式2:迭代器(可能更高效)
    let sum: i32 = matrix.iter()
                         .flat_map(|row| row.iter())
                         .sum();
    println!("迭代器求和: {}", sum);
}

11. 常见错误与解决方案

错误1:索引越界

fn main() {
    let matrix = vec![
        vec![1, 2, 3],
        vec![4, 5],
    ];
    
    // 错误:假设所有行长度相同
    // for i in 0..3 {
    //     for j in 0..3 {
    //         println!("{}", matrix[i][j]);  // 可能越界
    //     }
    // }
    
    // 解决方案:使用迭代器或检查长度
    for (i, row) in matrix.iter().enumerate() {
        for (j, &val) in row.iter().enumerate() {
            println!("matrix[{}][{}] = {}", i, j, val);
        }
    }
}

错误2:无限嵌套循环

fn main() {
    // 错误:缺少退出条件
    // let mut i = 0;
    // loop {
    //     let mut j = 0;
    //     loop {
    //         j += 1;
    //         // 没有break条件
    //     }
    // }
    
    // 解决方案:添加明确的退出条件
    let mut i = 0;
    'outer: loop {
        let mut j = 0;
        loop {
            j += 1;
            if j >= 3 {
                break;  // 退出内层循环
            }
        }
        i += 1;
        if i >= 3 {
            break 'outer;  // 退出外层循环
        }
    }
}

错误3:错误的标签使用

fn main() {
    // 错误:标签名称拼写错误或作用域问题
    // 'outer: for i in 1..=3 {
    //     for j in 1..=3 {
    //         break 'outter;  // 拼写错误!
    //     }
    // }
    
    // 正确:使用正确的标签名
    'outer: for i in 1..=3 {
        'inner: for j in 1..=3 {
            if j == 2 {
                break 'outer;  // 使用正确的标签
            }
        }
    }
}

12. 扩展练习

练习1:矩阵操作

实现矩阵的加法、减法、乘法和转置操作。

练习2:打印图案

编写函数打印各种图案(金字塔、菱形、心形等)。

练习3:数独验证器

使用嵌套循环检查数独棋盘是否有效。

练习4:二维搜索

在一个排序的二维矩阵中高效查找目标值(考虑矩阵的排序特性)。

练习5:组合生成器

生成从n个元素中选取k个元素的所有组合。

练习6:图像卷积

实现简单的图像卷积操作(使用嵌套循环)。

13. 总结

核心要点回顾

  1. 嵌套循环结构:可以任意组合不同类型的循环
  2. 循环标签:使用标签控制外层循环的break和continue
  3. 执行顺序:外层循环一次迭代,内层循环完整执行
  4. 常见应用:矩阵运算、搜索、图案打印、排列组合
  5. 性能考虑:合理使用提前退出,考虑使用迭代器

关键特性

  • 灵活性:支持任意深度的嵌套
  • 标签控制:精确控制嵌套循环的流程
  • 表达能力:能够处理复杂的多维问题
  • 性能优化:支持多种优化策略

最佳实践

  • 控制嵌套深度:通常不超过3层,超过则考虑重构
  • 使用有意义的标签名:提高代码可读性
  • 及时退出:找到目标后立即退出,避免不必要的计算
  • 考虑迭代器:某些场景下迭代器可能更清晰、更高效
  • 添加注释:复杂嵌套逻辑需要注释说明
Logo

新一代开源开发者平台 GitCode,通过集成代码托管服务、代码仓库以及可信赖的开源组件库,让开发者可以在云端进行代码托管和开发。旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐