流程控制
rust代码是从上至下顺序执行的,在这个过程中,可以通过循环,分支等流程控制方式来实现相应的逻辑。
if-else
rust的if-else和其它语言中的类似,但是if-else在rust中是一个表达式,并且所有分支必须返回相同的类型。下面通过例子来具体看看。
代码语言:javascript复制fn main() {
let a = 1;
let b = 2;
if a > b {
println!("{}", "a>b");
}else {
println!("{}", "a<=b");
}
let c = if a > b {
println!("{}", "a>b");
a
}else {
println!("{}", "a<=b");
b
}; // 当if-else表达式的值被let语句使用的时候,需要在最后加上分号,并且保证a,b返回的值是同类型。
println!("{}", c); // c的值是由if表达式执行到的分支所确定的,因此c的值是2
}
rust的条件表达式不需要使用括号包括起来。除此之外rust的if表达式还有一个if let,由于if let本质上是和match一样的模式匹配,不在此处描述。
使用else if处理多重条件
和其它语言类似,rust的if-else语句可以有大量的分支用来处理多重条件。例如:
代码语言:javascript复制fn main() {
let n = 6;
if n % 4 == 0 {
println!("number is divisible by 4");
} else if n % 3 == 0 {
println!("number is divisible by 3");
} else if n % 2 == 0 {
println!("number is divisible by 2");
} else {
println!("number is not divisible by 4, 3, or 2");
}
}
程序执行时,会按照自上至下的顺序执行每一个分支判断,一旦成功,则跳出 if 语句块,最终本程序会匹配执行 else if n % 3 == 0 的分支,输出 “number is divisible by 3”。有一点要注意,就算有多个分支能匹配,也只有第一个匹配的分支会被执行!(例如这段代码中的number is divisible by 2虽然匹配成功,但是不会被执行。)
for循环
rust的for循环和python,javascript的for循环看起来很像,语义如下:
代码语言:javascript复制for 元素 in 集合 {
// 使用元素
}
注意,使用 for 时我们往往使用集合的引用形式,这能避免集合的所有权转移。(除非你之后不再使用该集合),如果是实现了Copy trait的数组,那么不会导致所有权的转移。如果想在循环中,修改该元素,可以使用mut关键字。例如:
代码语言:javascript复制for num in &mut nums { // 可变引用,修改元素的值
*num = 3; // 注意这里需要手动解引用,
}
println!("{:?}", nums);
获取元素索引
在循环中获取元素的索引,可以使用下面的方式。
代码语言:javascript复制for (i, v) in nums.iter().enumerate() {
println!("第{}个元素是{}", i, v);
}
下表是可变引用,不可变引用,转移所有权的等价使用方式。
使用方法 | 等价使用方式 | 所有权 |
---|---|---|
for item in collection | for item in IntoIterator::into_iter(collection) | 转移所有权 |
for item in &collection | for item in collection.iter() | 不可变借用 |
for item in &mut collection | for item in collection.iter_mut() | 可变借用 |
for循环能够对迭代器进行循环迭代。(正如上面表格中的等价形式一样,for是对迭代器进行的。) |
控制循环执行次数
下面是一个使用for循环控制循环体执行10次的例子。
代码语言:javascript复制for i in 0..10 {
println!("{}", i);
}
如果你不需要使用i,那么可以使用_来代替。在 Rust 中 _ 的含义是忽略该值或者类型的意思,如果不使用 _,那么编译器会给你一个 变量未使用的 的警告。例如:
代码语言:javascript复制for _ in 0..=10 {
println!("Hello rust!");
}
continue
和其它编程语言一样,continue都是跳过本次循环,开始下次循环。例如:
代码语言:javascript复制for i in 0..=10{
if i % 2 == 0 {
continue;
}
println!("{}", i);
}
程序执行结果如下所示:
代码语言:javascript复制1
3
5
7
9
break
和其它编程语言一样,break可以跳出整个循环,使当前循环结束。例如:
代码语言:javascript复制for i in 1..9 {
if i == 5 {
break;
}
println!("{}", i);
}
程序执行结果如下所示:
代码语言:javascript复制1
2
3
4
while循环
while循环相比for循环,可能没有那么常用。当循环条件为 true 时,继续循环,条件为 false,跳出循环。例如:
代码语言:javascript复制let mut count = 0;
while count < 3 {
println!("{}", count);
count = 1;
}
loop循环
rust提供了loop循环,它是一个简单的无限循环。因此在使用loop循环的时候要格外小心,如果你忘记配合break来使用,那程序可能就在循环里永远出不来了。另外一点是loop循环是一个表达式,而for和while循环不是。例如:
代码语言:javascript复制let result = loop {
count = 1;
if count == 10 {
break count * 2;
}
};
println!("{}", result);
这段代码中,通过break带回了返回值。打印出20
循环标签
和大多数语言一样,再存在多层循环嵌套的情况下,break 和 continue 应用于此时最内层的循环。rust提供了标签结合continue,break来使用,使这些标签应用于已标记的循环而不是内层的循环。例如:
代码语言:javascript复制fn main() {
let mut count = 0;
'outer: loop {
'inner1: loop {
if count >= 20 {
// 这只会跳出 inner1 循环
break 'inner1; // 这里使用 `break` 也是一样的
}
count = 2;
}
count = 5;
'inner2: loop {
if count >= 30 {
break 'outer;
}
continue 'outer;
}
}
assert!(count == 30)
}
这段代码需要仔细看,不能大意。因为有的break和continue是跳到某一个标签,而不是最内层的循环。循环标签使得循环更加强大,但是带来的后果是使得代码的逻辑变得更加复杂难懂。非必要不使用循环标签。
参考资料
- rust程序设计语言
- rust语言圣经