3.6.0. 写在正文之前
欢迎来到Rust自学的第三章,一共有6个小节,分别是:
- 变量与可变性
- 数据类型:标量类型
- 数据类型:复合类型
- 函数和注释
- 控制流:
if else
- 控制流:循环(本文)
通过第二章的小游戏(没看的初学者强烈建议看一下),相信你已经学会了基本的Rust语法,而在第三章我们将更深一层,了解Rust中的通用的编程概念。
喜欢的话记得点赞、收藏加关注哦,想要跟着学下去记得关注专栏哦
3.6.1. Rust的循环
Rust一共提供了三种循环:
loop
while
for
3.6.2. loop循环
loop
关键字告诉Rust要反复执行一段代码,除非喊停。以下是一个例子,它会不断打印6657 up up!
。
fn main(){loop {println!("6657 up up!");}
}
可以在loop
循环中使用break
关键字来告诉程序何时停止
fn main(){let mut counter = 0;let result = loop {counter += 1;if counter == 10 {break counter * 2;}};println!("The result is:{}", result);
}
代码逻辑描述:
- counter 初始化为 0,在每次循环中递增 1。
- 当 counter 等于 10 时,break 退出循环,同时返回 counter * 2(即 20)。
- loop 是一个表达式,其返回值是 break 的返回值,因此可以直接赋值给 result。
- result 最终打印出 20。
代码特点:
- Rust 的 loop 是表达式,可以直接绑定结果到变量。
- break 可以携带返回值(这里是 counter * 2),并作为 loop 的结果。
- let 语句要求赋值表达式后需要加分号(;),因此 loop 的结束大括号 } 后需加分号。
3.6.3. while条件循环
while
循环在每次执行循环体之前都要判断一次条件
fn main() {let mut countdown = 10; // 倒计时从10开始println!("Rocket Launch Countdown:");while countdown > 0 {println!("T-minus {}...", countdown);countdown -= 1; // 每次减少1}println!("🚀 Liftoff!");println!("Huston, we have a problem.");
}
这是一个简单的while
循环示例代码,其运行结果是:
Rocket Launch Countdown:
T-minus 10...
T-minus 9...
T-minus 8...
T-minus 7...
T-minus 6...
T-minus 5...
T-minus 4...
T-minus 3...
T-minus 2...
T-minus 1...
🚀 Liftoff!
Huston, we have a problem
3.6.4. 使用for循环遍历集合
当然也可以使用while
和loop
来遍历集合,但是易错且低效
这是个使用while
的例子:
fn main() {let numbers = [10, 20, 30, 40, 50];let mut index = 0;println!("Using while loop:");while index < 5 {println!("Number at index {}: {}", index, numbers[index]);index += 1;}
}
使用while
时极有可能造成索引越界触发panic!
,而且运行速度较慢,因为每次都要检查index < 5
这个条件。
这是个使用for
的例子(实现同样的效果):
fn main() {let numbers = [10, 20, 30, 40, 50];println!("Using for loop:");for (index, number) in numbers.iter().enumerate() {println!("Number at index {}: {}", index, number);}
}
1. numbers.iter()
- 调用集合
numbers
的.iter()
方法,创建一个不可变的迭代器,用于逐个访问集合中的元素。在 Rust 中,for 循环并不直接操作集合,而是操作实现了Iterator
特征的迭代器。.iter()
是 Vec(或其他集合)常用的方法,生成一个指向集合元素的引用的迭代器。使用for
循环简洁紧凑,它可以针对集合中的每个元素来执行代码。由于for
循环的安全性、简洁性,所以它在Rust中使用最多
2. .enumerate()
• 为迭代器的每个元素附加一个索引。索引从 0 开始,是一个usize
类型的值。.enumerate()
将迭代器的每个元素包装成 (index, value)
的形式,其中:index
是元素在集合中的索引。value
是当前迭代器指向的元素。.enumerate()
返回一个新的迭代器,迭代出的元素类型是 (usize, &T)
,其中 T
是集合中元素的类型。在这里,numbers
是一个Vec<i32>
,因此&T
是&i32
。
3. for (index, number) in ...
• for 循环支持解构元组,(index, number)
表示我们直接将 enumerate()
提供的 (usize, &T)
元组解构成两个变量:index
:当前元素的索引。number
:当前元素的引用(不可变)。
假设 numbers
是 [10, 20, 30, 40, 50]
,执行时的过程如下:
- 调用
numbers.iter()
创建迭代器。 - 调用
.enumerate()
,生成 (索引, 元素引用) 的迭代器 for
循环解构出索引和元素:- 第一次循环:
index = 0, number = &10
- 第二次循环:
index = 1, number = &20
- 第三次循环:
index = 2, number = &30
- …
- 第一次循环:
- 打印
index
和number
,输出每个元素的索引和值。
由于使用for
循环呢的安全、简洁性,所以它在Rust里使用最多。
3.6.5. Range
Range
由标准库提供。用户可以通过Range
生成它们之间的数字(不含结束)。使用rev
方法可以反转Range
。
fn main() {println!("Rocket Launch Countdown:");for countdown in (1..=10).rev() {println!("T-minus {}...", countdown);}println!("🚀 Liftoff!");println!("Huston, we have a problem.");
}
这个例子使用for
循环、Range
和rev
实现了上文while
函数所实现的火箭倒数
代码解析
- (1…=10):
- 这是一个
Range
,表示从 1 到 10(包含 10)。 - …= 是包含上限的范围操作符。
- 这是一个
- .rev():
- 反转迭代器,生成一个从 10 到 1 的递减序列。