循环
1.1 loop
在Rust中,使用loop表示一个无限死循环。示例如下:
fn main() {
let mut count = 0u32;
println!("Let's count until infinity!");
// 无限循环
loop {
count += 1;
if count == 3 {
println!("three");
// 不再继续执行后面的代码,跳转到loop开头继续循环
continue;
}
println!("{}", count);
if count == 5 {
println!("OK, that's enough");
// 跳出循环
break;
}
}
}
其中,我们可以使用continue和break控制执行流程。continue;
语句表示本次循环内,后面的语句不再执行,直接进入下一论循环。break;
语句表示跳出循环,不再继续。
另外,break语句和continue语句还可以在多重循环中选择跳出到哪一层的循环。
fn partice2() {
let mut m = 1;
let n = 1;
'a: loop {
if m < 100 {
m += 1;
} else {
loop {
if m + n > 50 {
println!("break");
break 'a;
} else {
continue 'a;
}
}
}
}
}
我们可以在loop、while、for循环前面加上声明周期标识符。该标识符以单引号开头,在内部的循环中可以使用break语句选择跳出到哪一层。
与if结构一样,loop结构也可以作为表达式的一部分。
fn main() {
let v = loop {
break 10;
};
println!("{}", v);
}
在loop内部break的后面可以跟一个表达式,这个表达式就是最终的loop表达式的值。如果一个loop永远不返回,那么它的类型就是发散类型。示例如下:
fn main() {
let v = loop {};
println!("{}", v);
}
编译器可以判断出v的类型是发散类型,而后面的打印语句是永远不会执行的死代码。
1.2 while
while语句是带条件判断的循环语句。其语法是while关键字后跟条件判断语句,最后是结果语句块。如果条件满足,则持续循环执行结果语句块。示例如下:
fn partice1() {
let mut n = 1;
while n < 101 {
if n % 15 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
}else {
println!("{}", n);
}
n += 1;
}
}
同理,while语句中也可以使用continue和break来控制循环流程。
那么loop {}
和while true {}
循环有什么区别,为什么Rust专门设计了一个死循环,loop语句难道不是完全多余的么?
实际上不是。主要原因在于,相比于其他的许多语言,Rust语言要做更多的静态分析。loop和while true语句在运行时没有什么区别,他们主要是会影响编译器内部的静态分析结果。比如:
let x;
loop { x = 1; break; }
println!("{}", x)
以上语句在Rust中完全合理。因为编译器可以通过流程分析推理出x=1;必然在println!之前执行过,因此打印变量x的值是完全合理的。而下面的代码是编译不过的:
let x;
while true { x = 1; break; }
println!("{}", x);
因为编译器会觉得while语句的执行跟条件表达式在运行阶段的值有关,因此它不确定x是否一定会初始化,于是它决定给出一个错误: use of possibly uninitialized variable,也就是说变量x可能没有初始化。
1.3 for
Rust中的for循环实际上是许多其他语言中的for-each循环。Rust中没有类似C/C++的三段式for循环语句。举例如下:
fn partice1() {
let array = &[1, 2, 3, 4, 5];
for i in array{
println!("The numver is {}", i)
}
}
for循环的主要用处是利用迭代器对包含同样类型的多个元素的容器执行遍历,如数组、链表、HashMap、HashSet等。在Rust中,我们可以很轻松的定制容器和迭代器,因此也很容易使for循环也支持自定义类型。
for循环内部也可以使用continue和break控制执行流程。
正序输出1-10
fn partice2() {
for num in 1..10 {
println!("number is :{num}")
}
}
倒序输出1-10
fn partice3() {
for num in (1..10).rev() {
println!("number is :{num}")
}
}