条件控制
Rust的条件控制也是使用if else,和其他语言相比没有多大区别,直接看例子:
fn main()
{
let number = 10;
if number < 0
{
println!("number小于0");
}
else if 0 <= number && number <= 5
{
println!("number在0~5之间");
}
else if number > 5 && number <= 10
{
println!("number在5~10之间");
}
else
{
println!("number大于10");
}
}
一定要牢记Rust是基于表达式的语言,除了声明语句和表达式语句外,其他的都是表达式。所以if也是表达式,它可以被用作右值。如:
fn main()
{
let number = 10;
let condition = if number < 0
{
1
}
else if 0 <= number && number <= 10
{
2
}
else
{
3
};
println!("condition is {}", condition);
}
循环控制
Rust提供了三种循环方式:
- for
- while
- loop
for
Rust的for很像Python,可以遍历一个迭代器,如:
for x in 0..10
{
println!("{}", x);
}
Rust的类型大都内置了迭代器,可以直接进行遍历。如:
fn main()
{
// 遍历数组
let a = [1,2,3,4,5];
for x in a.iter()
{
println!("{}", x);
}
// 遍历切片
for x in a[..].iter()
{
println!("{}", x);
}
// 遍历字符串
let b = "hello";
for x in b.chars()
{
println!("{}", x);
}
// 遍历动态数组
let c = vec![1,2,3,4,5];
for x in c.iter()
{
println!("{}", x);
}
}
需要注意的是,使用迭代器遍历,得到的不是值本身,而是对值的引用,如:
fn main()
{
let a = [1, 2, 3, 4, 5, 6, 7, 8];
for v in a.iter()
{
if v == 3
{
println!("found");
}
}
}
编译会报错:
error[E0277]: can't compare `&{integer}` with `{integer}`
--> src\main.rs:6:14
|
6 | if v == 3
| ^^ no implementation for `&{integer} == {integer}`
|
= help: the trait `std::cmp::PartialEq<{integer}>` is not implemented for `&{integer}`
error: aborting due to previous error
此时,需要在v前面加*,类似于C/C++的指针:
fn main()
{
let a = [1, 2, 3, 4, 5, 6, 7, 8];
for *v in a.iter()
{
if v == 3
{
println!("found");
}
}
}
像Python那样,Rust也提供了enumerate函数,来记录循环的次数:
fn main()
{
// 遍历数组
let a = [1,2,3,4,5];
for (i, x) in a.iter().enumerate() // enumerate是迭代器的函数
{
println!("{}:{}", i, x);
}
}
while
Rust的while循环和大多数语言那样,没有什么特殊性:
fn main()
{
let mut number = 10;
while number > 0
{
println!("{}", number);
number -= 1;
}
}
loop
Rust比其他语言多了一个loop循环,loop就相当于while true,它没有结束的条件,只要没有break就一直循环下去。当然,这不仅仅是写法上的不同,编译器会对loop循环做更多的优化,来保证循环执行的效率和安全性更高。
fn main()
{
let mut number = 10;
loop
{
println!("{}", number);
number -= 1;
if number == 0
{
break;
}
}
}
break/continue
令人兴奋的是,Rust赋予break/continue强大的功能。使循环控制变得更加有趣。
- 跳出到指定的标签
Rust可以为循环指定标签,有多层循环嵌套时,可以直接指定跳出哪个循环:fn main() { let (mut i, mut j) = (0, 0); 'outer: loop { 'inner: loop { j += 1; println!("i={}, j={}", i, j); if j == 10 { break 'outer; // 跳出外层循环 } } i += 1; } }
fn main() { let (mut i, mut j) = (0, 0); 'outer: loop { i += 1; j = 0; 'inner: loop { j += 1; println!("i={}, j={}", i, j); if j == 10 { continue 'outer; // 继续外层循环 } } } }
- 作为右值
还是那句话,Rust是基于表达式的语言,这赋予了Rust很多新的特性。像前面提到的if是表达式一样,loop和break都是表达式,同样可以作为右值:fn main() { let a = [1, 2, 3, 4, 5, 6, 7, 8]; let mut index:usize = 0; // 从数组a中查找是否有0 let found = loop { if a[index] == 0 { break true } if index == a.len() - 1 { break false } index += 1; }; println!("found = {}", found); }
模式匹配
C/C++中有switch,可以控制多个流程分支。Rust把switch进行了升级,提供了match关键字,这是一个非常强大的控制流运算符,被称为模式匹配。
假如我们有一堆硬币,面值1元、0.5元0.1元,分别统计硬币的个数:
fn main()
{
let corns = [1.0, 0.5, 0.5, 1.0, 0.1, 1.0, 1.0, 0.5, 0.5, 1.0, 1.0, 1.0, 0.1];
let (mut c1, mut c2, mut c3) = (0, 0, 0);
for v in corns.iter()
{
match *v
{
1.0 => c1 += 1,
0.5 => c2 += 1,
0.1 => c3 += 1,
_ => break
}
}
println!("有1元硬币{}个, 5角硬币{}个,1角硬币{}个。", c1, c2, c3);
}
这种用法与C/C++中switch的用法类似,只是每个分支不需要加break。
在Rust中,match后面跟一个表达式,然后是分支。每个分支又分成两个部分,=>前面的部分叫模式,=>后面是执行体。
match执行时,先计算表达式的值,然后用该值与模式逐一进行匹配,当匹配成功时,执行该模式对应的执行体。若多个模式都匹配,也只执行第一个匹配成功的执行体。模式必须能覆盖所有的可能性,可以使用“_”,匹配其他的情况,类似于C/C++的default。
Rust的模式匹配功能非常强大,我试图跳过一些内容去理解模式匹配,但是确实有很多地方看不明白,需要等到学习到一定阶段才能去学习。