首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Rust专项——循环详解:掌握重复执行的艺术

Rust专项——循环详解:掌握重复执行的艺术

作者头像
红目香薰
发布2025-12-16 16:06:31
发布2025-12-16 16:06:31
660
举报
文章被收录于专栏:CSDNToQQCodeCSDNToQQCode

引言

循环是编程中重复执行代码块的基本构造。Rust提供了三种主要的循环类型:

  • loop:无限循环,需要显式break退出
  • while:条件循环,条件为false时退出
  • for:范围循环,迭代集合或范围

Rust的循环还有一个独特特性:循环也可以返回值!这使得循环在Rust中也是表达式,可以与其他表达式组合使用。

本文将全面介绍Rust的循环系统,包括:

  • loop无限循环及其返回值
  • while条件循环
  • for范围循环和迭代器
  • break和continue控制流
  • 循环标签(loop labels)
  • 嵌套循环
  • 最佳实践和性能考虑

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

  • 熟练使用三种循环类型
  • 理解循环返回值的特性
  • 掌握循环控制语句
  • 编写高效的循环代码

1. loop无限循环

1.1 基本的loop循环

loop 关键字创建了一个无限循环,必须使用 break 才能退出:

代码语言:javascript
复制
fn main() {
    loop {
        println!("无限循环!按Ctrl+C退出");
        // 在真实程序中,你需要某种条件来break
    }
}
1.2 使用break退出循环
代码语言:javascript
复制
fn main() {
    let mut counter = 0;
    
    loop {
        println!("计数: {}", counter);
        counter += 1;
        
        if counter >= 5 {
            break;  // 退出循环
        }
    }
    
    println!("循环结束");
}
在这里插入图片描述
在这里插入图片描述
1.3 loop返回值(重要特性!)

这是Rust循环最独特的特性loop 可以返回值!

代码语言:javascript
复制
fn main() {
    let mut counter = 0;
    
    // loop表达式返回break语句的值
    let result = loop {
        counter += 1;
        
        if counter == 10 {
            break counter * 2;  // 返回 20
        }
    };
    
    println!("结果: {}", result);  // 20
}
在这里插入图片描述
在这里插入图片描述

关键规则

  • break 后面可以跟一个值,这个值会成为loop表达式的返回值
  • 所有 break 的值类型必须相同
  • 如果没有返回值,loop返回单元类型 ()
1.4 带返回值的loop示例
代码语言:javascript
复制
fn main() {
    // 示例1:查找第一个满足条件的数
    let result = loop {
        static mut COUNTER: u32 = 0;
        unsafe {
            COUNTER += 1;
            if COUNTER > 100 {
                break None;  // 没找到
            }
            if COUNTER % 7 == 0 && COUNTER % 13 == 0 {
                break Some(COUNTER);  // 找到了
            }
        }
    };
    
    match result {
        Some(n) => println!("找到的数字: {}", n),
        None => println!("未找到"),
    }
    
    // 示例2:重试机制
    let mut attempts = 0;
    let success = loop {
        attempts += 1;
        println!("尝试 {}...", attempts);
        
        // 模拟操作(实际中可能是网络请求等)
        if attempts >= 3 {
            break false;  // 失败
        }
        if attempts == 2 {
            break true;   // 成功
        }
    };
    
    if success {
        println!("操作成功!");
    } else {
        println!("操作失败!");
    }
}
在这里插入图片描述
在这里插入图片描述

2. while条件循环

2.1 基本的while循环

while 循环在条件为 true 时持续执行:

代码语言:javascript
复制
fn main() {
    let mut number = 3;
    
    while number != 0 {
        println!("{}!", number);
        number -= 1;
    }
    
    println!("发射!");
}
在这里插入图片描述
在这里插入图片描述
2.2 while循环的条件

条件必须是 bool 类型:

代码语言:javascript
复制
fn main() {
    let mut counter = 0;
    
    // 正确:使用bool条件
    while counter < 5 {
        println!("计数: {}", counter);
        counter += 1;
    }
    
    // 错误:不能使用数字作为条件
    // while counter {
    //     ...
    // }
    
    let mut option = Some(0);
    
    // 使用Option的判断
    while let Some(i) = option {
        if i > 2 {
            option = None;
        } else {
            println!("数字: {}", i);
            option = Some(i + 1);
        }
    }
}
在这里插入图片描述
在这里插入图片描述
2.3 while循环的实际应用
代码语言:javascript
复制
fn main() {
    // 示例1:数组遍历
    let arr = [10, 20, 30, 40, 50];
    let mut index = 0;
    
    while index < arr.len() {
        println!("arr[{}] = {}", index, arr[index]);
        index += 1;
    }
    
    // 示例2:条件驱动的循环
    let mut guess = 50;
    let secret_number = 42;
    
    while guess != secret_number {
        if guess > secret_number {
            println!("太大了!");
            guess -= 1;
        } else {
            println!("太小了!");
            guess += 1;
        }
    }
    
    println!("猜对了!数字是 {}", secret_number);
}
在这里插入图片描述
在这里插入图片描述

3. for循环和迭代器

3.1 for循环遍历范围

for 循环是Rust中最常用的循环,通常用于遍历集合或范围:

代码语言:javascript
复制
fn main() {
    // 遍历范围(不包含5)
    for i in 1..5 {
        println!("{}", i);  // 1, 2, 3, 4
    }
    
    // 遍历范围(包含5)
    for i in 1..=5 {
        println!("{}", i);  // 1, 2, 3, 4, 5
    }
    
    // 反向遍历
    for i in (1..=5).rev() {
        println!("{}", i);  // 5, 4, 3, 2, 1
    }
}
在这里插入图片描述
在这里插入图片描述
3.2 for循环遍历数组和切片
代码语言:javascript
复制
fn main() {
    let arr = [10, 20, 30, 40, 50];
    
    // 遍历数组元素
    for element in arr.iter() {
        println!("元素: {}", element);
    }
    
    // 或者使用引用(更常用)
    for element in &arr {
        println!("元素: {}", element);
    }
    
    // 获取索引和值
    for (index, value) in arr.iter().enumerate() {
        println!("索引 {}: 值 {}", index, value);
    }
    
    // 可变遍历
    let mut numbers = [1, 2, 3, 4, 5];
    for num in numbers.iter_mut() {
        *num *= 2;
    }
    println!("修改后: {:?}", numbers);  // [2, 4, 6, 8, 10]
}
在这里插入图片描述
在这里插入图片描述
3.3 for循环遍历向量(Vec)
代码语言:javascript
复制
fn main() {
    let vec = vec![1, 2, 3, 4, 5];
    
    // 遍历向量
    for value in &vec {
        println!("值: {}", value);
    }
    
    // 获取所有权(会消耗向量)
    let vec = vec![10, 20, 30];
    for value in vec {
        println!("值: {}", value);
    }
    // vec 在这里已经被消耗,不能再使用
    
    // 遍历并修改
    let mut vec = vec![1, 2, 3, 4, 5];
    for num in vec.iter_mut() {
        *num *= 2;
    }
    println!("{:?}", vec);  // [2, 4, 6, 8, 10]
}
在这里插入图片描述
在这里插入图片描述
3.4 for循环遍历字符串
代码语言:javascript
复制
fn main() {
    let s = "Hello";
    
    // 遍历字符
    for ch in s.chars() {
        println!("字符: {}", ch);
    }
    
    // 遍历字节
    for byte in s.bytes() {
        println!("字节: {}", byte);
    }
    
    // 遍历字符及其索引
    for (i, ch) in s.char_indices() {
        println!("位置 {}: 字符 {}", i, ch);
    }
}
在这里插入图片描述
在这里插入图片描述
3.5 for循环的高级用法
代码语言:javascript
复制
fn main() {
    // 使用迭代器方法
    let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    // 过滤和映射
    for num in numbers.iter()
                     .filter(|&&x| x % 2 == 0)
                     .map(|&x| x * 2) {
        println!("偶数翻倍: {}", num);
    }
    
    // 跳过和限制
    for i in (1..=100).skip(10).take(5) {
        println!("{}", i);  // 11, 12, 13, 14, 15
    }
    
    // 步长
    for i in (0..10).step_by(2) {
        println!("{}", i);  // 0, 2, 4, 6, 8
    }
}
在这里插入图片描述
在这里插入图片描述

4. break和continue控制流

4.1 break语句

break 用于立即退出循环:

代码语言:javascript
复制
fn main() {
    let mut counter = 0;
    
    loop {
        counter += 1;
        
        if counter == 5 {
            break;  // 退出循环
        }
        
        println!("计数: {}", counter);
    }
    
    println!("循环在第 {} 次迭代时退出", counter);
}
4.2 continue语句

continue 用于跳过当前迭代,继续下一次迭代:

代码语言:javascript
复制
fn main() {
    for i in 1..=10 {
        if i % 2 == 0 {
            continue;  // 跳过偶数
        }
        println!("奇数: {}", i);  // 只打印 1, 3, 5, 7, 9
    }
}
4.3 break和continue在while中的使用
代码语言:javascript
复制
fn main() {
    let mut number = 0;
    
    while number < 10 {
        number += 1;
        
        if number == 3 {
            continue;  // 跳过3
        }
        
        if number == 8 {
            break;  // 在8时退出
        }
        
        println!("数字: {}", number);
    }
    // 输出: 1, 2, 4, 5, 6, 7
}
4.4 break和continue在for中的使用
代码语言:javascript
复制
fn main() {
    let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    for num in numbers {
        if num == 5 {
            continue;  // 跳过5
        }
        
        if num == 8 {
            break;  // 在8时退出
        }
        
        println!("数字: {}", num);
    }
    // 输出: 1, 2, 3, 4, 6, 7
}

5. 循环标签(Loop Labels)

5.1 为什么需要循环标签?

当有嵌套循环时,有时候需要从内层循环退出外层循环,这时就需要循环标签:

代码语言:javascript
复制
fn main() {
    // 没有标签的情况
    'outer: loop {
        println!("外层循环");
        
        'inner: loop {
            println!("内层循环");
            break 'outer;  // 退出外层循环
        }
        
        // 这里的代码不会执行
    }
    
    println!("退出所有循环");
}
5.2 循环标签的实际应用
代码语言:javascript
复制
fn main() {
    let matrix = vec![
        vec![1, 2, 3],
        vec![4, 5, 6],
        vec![7, 8, 9],
    ];
    
    'search: for (row_idx, row) in matrix.iter().enumerate() {
        for (col_idx, &value) in row.iter().enumerate() {
            if value == 5 {
                println!("找到5在位置 ({}, {})", row_idx, col_idx);
                break 'search;  // 退出外层循环
            }
        }
    }
}
5.3 continue与标签配合使用
代码语言:javascript
复制
fn main() {
    'outer: for i in 1..=3 {
        'inner: for j in 1..=3 {
            if j == 2 {
                continue 'outer;  // 继续外层循环的下一次迭代
            }
            println!("i={}, j={}", i, j);
        }
    }
    // 输出:
    // i=1, j=1
    // i=2, j=1
    // i=3, j=1
}

6. 嵌套循环

6.1 基本嵌套循环
代码语言:javascript
复制
fn main() {
    // 打印九九乘法表
    for i in 1..=9 {
        for j in 1..=i {
            print!("{}×{}={}\t", j, i, i * j);
        }
        println!();
    }
}
6.2 嵌套循环的不同类型组合
代码语言:javascript
复制
fn main() {
    // while嵌套for
    let mut outer = 0;
    while outer < 3 {
        for i in 1..=3 {
            println!("外层: {}, 内层: {}", outer, i);
        }
        outer += 1;
    }
    
    // loop嵌套while
    let mut counter = 0;
    loop {
        let mut inner = 0;
        while inner < 2 {
            println!("外层计数: {}, 内层: {}", counter, inner);
            inner += 1;
        }
        counter += 1;
        if counter >= 3 {
            break;
        }
    }
}

7. 循环与迭代器方法

7.1 使用迭代器替代循环

Rust的迭代器提供了函数式编程风格,有时比循环更清晰:

代码语言:javascript
复制
fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    
    // 使用for循环
    let mut sum = 0;
    for num in &numbers {
        sum += num;
    }
    println!("循环求和: {}", sum);
    
    // 使用迭代器(更函数式)
    let sum: i32 = numbers.iter().sum();
    println!("迭代器求和: {}", sum);
    
    // 更多迭代器方法
    let doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();
    println!("翻倍: {:?}", doubled);
    
    let evens: Vec<i32> = numbers.iter()
                                 .filter(|&x| x % 2 == 0)
                                 .copied()
                                 .collect();
    println!("偶数: {:?}", evens);
}
7.2 何时使用循环vs迭代器

场景

推荐

原因

简单遍历

for循环

更直观

数据转换

迭代器

更函数式,可链式调用

条件查找

迭代器(find)

更简洁

副作用操作

循环

需要执行副作用

复杂控制流

循环

需要break/continue

8. 实际应用示例

示例1:查找数组中的元素
代码语言:javascript
复制
fn main() {
    let arr = [10, 20, 30, 40, 50];
    let target = 30;
    
    // 使用for循环查找
    let mut found = false;
    let mut index = None;
    
    for (i, &value) in arr.iter().enumerate() {
        if value == target {
            found = true;
            index = Some(i);
            break;
        }
    }
    
    match index {
        Some(i) => println!("找到 {} 在索引 {}", target, i),
        None => println!("未找到 {}", target),
    }
    
    // 使用迭代器(更简洁)
    if let Some(i) = arr.iter().position(|&x| x == target) {
        println!("找到 {} 在索引 {}", target, i);
    }
}
示例2:斐波那契数列生成器
代码语言:javascript
复制
fn main() {
    let n = 10;
    let mut fib = vec![0, 1];
    
    // 使用for循环生成
    for i in 2..n {
        let next = fib[i - 1] + fib[i - 2];
        fib.push(next);
    }
    
    println!("斐波那契数列: {:?}", fib);
    
    // 使用loop生成(另一种方式)
    let mut a = 0;
    let mut b = 1;
    let mut count = 0;
    
    loop {
        if count >= n {
            break;
        }
        print!("{} ", a);
        let next = a + b;
        a = b;
        b = next;
        count += 1;
    }
    println!();
}
示例3:猜数字游戏循环
代码语言:javascript
复制
fn main() {
    let secret_number = 42;
    let mut attempts = 0;
    let max_attempts = 5;
    
    loop {
        attempts += 1;
        
        if attempts > max_attempts {
            println!("游戏结束!答案是 {}", secret_number);
            break;
        }
        
        // 模拟用户猜测(实际中需要从输入读取)
        let guess = attempts * 10;  // 模拟:10, 20, 30, 40, 50
        
        println!("尝试 {}: 猜测 {}", attempts, guess);
        
        if guess == secret_number {
            println!("恭喜!你在 {} 次尝试后猜对了!", attempts);
            break;
        } else if guess < secret_number {
            println!("太小了!");
        } else {
            println!("太大了!");
        }
    }
}
示例4:数据处理流水线
代码语言:javascript
复制
fn main() {
    let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    // 使用迭代器链式处理
    let result: Vec<i32> = numbers
        .iter()
        .filter(|&&x| x % 2 == 0)  // 过滤偶数
        .map(|&x| x * x)            // 平方
        .filter(|&x| x > 20)        // 过滤大于20的
        .collect();
    
    println!("处理结果: {:?}", result);
    
    // 使用for循环实现相同功能
    let mut result2 = Vec::new();
    for num in numbers {
        if num % 2 == 0 {
            let squared = num * num;
            if squared > 20 {
                result2.push(squared);
            }
        }
    }
    println!("循环结果: {:?}", result2);
}

9. 常见错误与解决方案

错误1:无限循环
代码语言:javascript
复制
fn main() {
    // 问题:没有退出条件
    // let mut x = 0;
    // loop {
    //     x += 1;
    //     println!("{}", x);
    // }
    
    // 解决方案:添加退出条件
    let mut x = 0;
    loop {
        x += 1;
        if x > 10 {
            break;
        }
        println!("{}", x);
    }
}
错误2:类型不匹配
代码语言:javascript
复制
fn main() {
    // 错误:break返回值的类型不一致
    // let result = loop {
    //     if true {
    //         break 5;      // i32
    //     } else {
    //         break "five";  // &str - 类型不匹配!
    //     }
    // };
    
    // 解决方案:返回相同类型
    let result = loop {
        if true {
            break Some(5);
        } else {
            break None;
        }
    };
}
错误3:使用break返回值但没有值
代码语言:javascript
复制
fn main() {
    let mut counter = 0;
    
    // 这个loop返回 ()
    let result = loop {
        counter += 1;
        if counter >= 5 {
            break;  // 没有返回值
        }
    };
    
    println!("结果: {:?}", result);  // ()
    
    // 如果需要返回值
    let result2 = loop {
        counter += 1;
        if counter >= 5 {
            break counter * 2;  // 返回 10
        }
    };
    
    println!("结果: {}", result2);  // 10
}
错误4:在for循环中修改迭代的元素
代码语言:javascript
复制
fn main() {
    let mut numbers = vec![1, 2, 3, 4, 5];
    
    // 错误:不能在迭代时修改
    // for num in numbers.iter() {
    //     *num *= 2;  // 编译错误!iter() 返回不可变引用
    // }
    
    // 解决方案1:使用iter_mut()
    for num in numbers.iter_mut() {
        *num *= 2;
    }
    println!("修改后: {:?}", numbers);
    
    // 解决方案2:使用索引
    let mut numbers2 = vec![1, 2, 3, 4, 5];
    for i in 0..numbers2.len() {
        numbers2[i] *= 2;
    }
    println!("修改后: {:?}", numbers2);
}

10. 性能考虑

10.1 循环vs迭代器性能
代码语言:javascript
复制
fn main() {
    let numbers: Vec<i32> = (1..=1_000_000).collect();
    
    // 方式1:for循环
    let start = std::time::Instant::now();
    let mut sum1 = 0;
    for num in &numbers {
        sum1 += num;
    }
    let duration1 = start.elapsed();
    println!("for循环耗时: {:?}", duration1);
    
    // 方式2:迭代器
    let start = std::time::Instant::now();
    let sum2: i32 = numbers.iter().sum();
    let duration2 = start.elapsed();
    println!("迭代器耗时: {:?}", duration2);
    
    // 注意:在发布模式下,两者性能通常相同(零成本抽象)
}
10.2 避免不必要的分配
代码语言:javascript
复制
fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    
    // 不推荐:每次都创建新的向量
    // let doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();
    
    // 如果不需要分配,直接使用迭代器
    for doubled in numbers.iter().map(|x| x * 2) {
        println!("{}", doubled);
    }
}

11. 扩展练习

练习1:数字求和

使用不同的循环方式计算1到100的和(for循环、while循环、loop循环)。

练习2:查找素数

使用循环找出1到100之间的所有素数。

练习3:字符串反转

使用循环和迭代器两种方式反转一个字符串。

练习4:嵌套循环打印图案

使用嵌套循环打印各种图案(三角形、菱形等)。

练习5:平均值计算器

编写程序计算一组数字的平均值,使用迭代器和循环两种方式。

练习6:break返回值练习

编写一个loop循环,根据条件返回不同的值。

12. 总结

核心要点回顾
  1. 三种循环类型:loop(无限)、while(条件)、for(迭代)
  2. 循环返回值:loop和for可以返回值
  3. 控制流:break退出循环,continue跳过当前迭代
  4. 循环标签:用于控制嵌套循环
  5. 迭代器:函数式风格,可以与循环互换
关键特性
  • 表达式特性:loop可以返回值
  • 类型安全:所有break返回值类型必须一致
  • 零成本抽象:迭代器编译后与循环性能相同
  • 灵活性:三种循环适应不同场景
选择指南

场景

推荐

原因

需要无限循环直到条件满足

loop

明确的退出点

基于条件的重复

while

简洁的条件判断

遍历集合或范围

for

最常用,最安全

需要返回值

loop

可以返回break的值

函数式处理

迭代器

链式调用,可读性强

下一步学习

掌握了循环后,下一步我们将学习:

  • match表达式:强大的模式匹配工具
  • 函数:函数定义、参数和返回值
  • 所有权系统:理解Rust的内存管理核心
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-10-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言
  • 1. loop无限循环
    • 1.1 基本的loop循环
    • 1.2 使用break退出循环
    • 1.3 loop返回值(重要特性!)
    • 1.4 带返回值的loop示例
  • 2. while条件循环
    • 2.1 基本的while循环
    • 2.2 while循环的条件
    • 2.3 while循环的实际应用
  • 3. for循环和迭代器
    • 3.1 for循环遍历范围
    • 3.2 for循环遍历数组和切片
    • 3.3 for循环遍历向量(Vec)
    • 3.4 for循环遍历字符串
    • 3.5 for循环的高级用法
  • 4. break和continue控制流
    • 4.1 break语句
    • 4.2 continue语句
    • 4.3 break和continue在while中的使用
    • 4.4 break和continue在for中的使用
  • 5. 循环标签(Loop Labels)
    • 5.1 为什么需要循环标签?
    • 5.2 循环标签的实际应用
    • 5.3 continue与标签配合使用
  • 6. 嵌套循环
    • 6.1 基本嵌套循环
    • 6.2 嵌套循环的不同类型组合
  • 7. 循环与迭代器方法
    • 7.1 使用迭代器替代循环
    • 7.2 何时使用循环vs迭代器
  • 8. 实际应用示例
    • 示例1:查找数组中的元素
    • 示例2:斐波那契数列生成器
    • 示例3:猜数字游戏循环
    • 示例4:数据处理流水线
  • 9. 常见错误与解决方案
    • 错误1:无限循环
    • 错误2:类型不匹配
    • 错误3:使用break返回值但没有值
    • 错误4:在for循环中修改迭代的元素
  • 10. 性能考虑
    • 10.1 循环vs迭代器性能
    • 10.2 避免不必要的分配
  • 11. 扩展练习
    • 练习1:数字求和
    • 练习2:查找素数
    • 练习3:字符串反转
    • 练习4:嵌套循环打印图案
    • 练习5:平均值计算器
    • 练习6:break返回值练习
  • 12. 总结
    • 核心要点回顾
    • 关键特性
    • 选择指南
    • 下一步学习
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档