Rust结构化编程
Rust结构化编程
条件判断
条件判断语句 | 说明 |
---|---|
if 语句 | if 语句用于模拟现实生活中的 如果…就… |
if...else 语句 | if...else 语句用于模拟 如果…就…否则… |
else...if 和嵌套if 语句 | 嵌套if 语句用于模拟 如果…就…如果…就… |
match 语句 | match 语句用于模拟现实生活中的 老师点名 或 银行叫 |
if 语句
if 条件表达式 {
// 条件表达式为true时要执行的逻辑
}
示例
let total:f32 = 666.00;
if total > 500.00 {
println!("打8折,{}",total*0.8)
}
// 输出 打8折,532.8
if …else 语句
if 条件表达式 {
// 如果 条件表达式 为真则执行这里的代码
} else {
// 如果 条件表达式 为假则执行这里的代码
}
示例
let total:f32 = 166.00;
if total > 500.00 {
println!("打8折,{}", total*0.8)
} else {
println!("无折扣优惠,{}", total)
}
输出 无折扣优惠,166
if…else if… else 语句
if 条件表达式1 {
// 当 条件表达式1 为 true 时要执行的语句
} else if 条件表达式2 {
// 当 条件表达式2 为 true 时要执行的语句
} else {
// 如果 条件表达式1 和 条件表达式2 都为 false 时要执行的语句
}
示例
let total:f32 = 366.00;
if total > 200.00 && total < 500.00 {
println!("打9折,{}",total*0.9)
} else if total > 500.00 {
println!("打8折,{}",total*0.9)
} else {
println!("无折扣优惠,{}",total)
}
// 输出 打9折,329.4
可以作为表达式赋值 (三元运算符)
if 语句是表达式而非语句
用 if
来赋值时,要保证每个分支返回的类型一样,如果返回类型不一致就会报错
if condition == true {
// A...
} else {
// B...
}
match 语句
Rust 中的 match 语句有返回值,它把 匹配值 后执行的最后一条语句的结果当作返回值。
语法
match variable_expression {
constant_expr1 => {
// 语句;
},
constant_expr2 => {
// 语句;
},
_ => {
// 默认
// 其它语句
}
};
示例
let code = "10010";
let choose = match code {
"10010" => "联通",
"10086" => "移动",
_ => "Unknown"
};
println!("选择 {}", choose); // 输出 选择 联通
let code = "80010";
let choose = match code {
"10010" => "联通",
"10086" => "移动",
_ => "Unknown"
};
println!("选择 {}", choose); // 输出 选择 Unknown
循环
现实中的循环很多,比如我们在学校操场里跑步,一圈一圈的跑。在计算机中,循环 其实就是一种重复,在满足指定的条件下,重复的做某些事情。
Rust 语言中也有三种表示 循环 的语句:
- loop 语句。一种重复执行且永远不会结束的循环。
- while 语句。一种在某些条件为真的情况下就会永远执行下去的循环。
- for in 语句。一种有确定次数的循环。
for in 循环
for 临时变量 in 集合 { // 常见用法:用 `左区间..右区间` 来构建一个序列集合
// 执行业务逻辑
}
左区间..右区间,这是一个左闭右开的区间,1..5,那就只包含 1,2,3,4
for num in 1..5 {
println!("num is {}", num);
}
// 输出
num is 1
num is 2
num is 3
num is 4
可以使用 a..=b 表示两端都包含在内的范围。
for num in 1..=5 {
println!("num is {}", num);
}
// 输出
num is 1
num is 2
num is 3
num is 4
num is 5
for in 与迭代器
2021版本后不用 .iter()
也行,但本质上还是因为隐式地转换成迭代器
iter (集合不变)
在每次迭代中借用集合中的一个元素。这样集合本身不会被改变,循环之后仍可以使用。
let studyList = vec![
"《Go语言极简一本通》",
"Go语言微服务架构核心22讲",
"从0到Go语言微服务架构师",
];
for name in studyList.iter() {
match name {
&"从0到Go语言微服务架构师" => println!("恭喜你进阶到第三阶段-{}!", name),
_ => println!("学习: {}", name),
}
}
// 输出
学习: 《Go语言极简一本通》
学习: Go语言微服务架构核心22讲
恭喜你进阶到第三阶段-从0到Go语言微服务架构师!
可以简化不写 .iter()
使用 for
时我们往往使用集合的引用形式,除非你不想在后面的代码中继续使用该集合(比如我们这里使用了 container
的引用)。如果不使用引用的话,所有权会被转移(move)到 for
语句块中,后面就无法再使用这个集合了)
for item in &container {
// ...
}
into_iter (消耗集合)
会消耗集合。在每次迭代中,集合中的数据本身会被提供。一旦集合被消耗了,之后就无法再使用了,因为它已经在循环中被 “移除”(move)了。
let studyList2 = vec![
"《Go语言极简一本通》",
"Go语言微服务架构核心22讲",
"从0到Go语言微服务架构师",
];
for name in studyList2.into_iter() {
match name {
"从0到Go语言微服务架构师" => println!("恭喜你进阶到第三阶段-{}!", name),
_ => println!("学习: {}", name),
}
}
// 输出
学习: 《Go语言极简一本通》
学习: Go语言微服务架构核心22讲
恭喜你进阶到第三阶段-从0到Go语言微服务架构师!
iter_mut (集合可改)
可变地(mutably)借用集合中的每个元素,从而允许集合被就地修改。
就是停止本次执行剩下的语句,直接进入下一个循环。
let mut studyList3 = vec![
"《Go语言极简一本通》",
"Go语言微服务架构核心22讲",
"从0到Go语言微服务架构师",
];
for name in studyList3.iter_mut() {
*name = match name {
&mut "从0到Go语言微服务架构师" => {
"恭喜你进阶到第三阶段---从0到Go语言微服务架构师"
}
_ => *name,
}
}
println!("studyList3: {:?}", studyList3);
// 输出
studyList3: ["《Go语言极简一本通》", "Go语言微服务架构核心22讲", "恭喜你进阶到第三阶段---从0到Go语言微服务架构师"]
可以简化不写 .iter_mut()
for item in &mut collection {
// ...
}
总结,比较各种循环方式
总结如下:
使用方法 | 等价使用方式 | 所有权 |
---|---|---|
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() | 可变借用 |
如果想在循环中获取元素的索引:
fn main() {
let a = [4, 3, 2, 1];
// `.iter()` 方法把 `a` 数组变成一个迭代器
for (i, v) in a.iter().enumerate() {
println!("第{}个元素是{}", i + 1, v);
}
}
两种循环方式优劣对比
以下代码,使用了两种循环方式:
// 第一种
let collection = [1, 2, 3, 4, 5];
for i in 0..collection.len() {
let item = collection[i];
// ...
}
// 第二种
for item in collection {
}
第一种方式是循环索引,然后通过索引下标去访问集合,第二种方式是直接循环集合中的元素,优劣如下:
- 性能:
- 第一种使用方式中
collection[index]
的索引访问,会因为边界检查(Bounds Checking)导致运行时的性能损耗 —— Rust 会检查并确认index
是否落在集合内 - 但是第二种直接迭代的方式就不会触发这种检查,因为编译器会在编译时就完成分析并证明这种访问是合法的
- 第一种使用方式中
- 安全:
- 第一种方式里对
collection
的索引访问是非连续的,存在一定可能性在两次访问之间,collection
发生了变化,导致脏数据产生。 - 而第二种直接迭代的方式是连续访问,因此不存在这种风险( 由于所有权限制,在访问过程中,数据并不会发生变化)。
- 第一种方式里对
由于 for
循环无需任何条件限制,也不需要通过索引来访问,因此是最安全也是最常用的
小技巧:省略i
有同学可能会想到,如果我们想用 for
循环控制某个过程执行 10 次,但是又不想单独声明一个变量来控制这个流程,该怎么写?
可以用 _
来替代 i
用于 for
循环中,在 Rust 中 _
的含义是忽略该值或者类型的意思,如果不使用 _
,那么编译器会给你一个 变量未使用的
的警告。
for _ in 0..10 {
// ...
}
while 循环
while ( 条件表达式 ) {
// 执行业务逻辑
}
上面的条件表达式为真,就会执行 while 循环。
let mut num = 1;
while num < 20 {
println!("num is {}",num);
num= num*2;
}
// 输出
num is 1
num is 2
num is 4
num is 8
num is 16
loop 循环+break
loop {
// 执行业务逻辑
}
break; 中断的意思,就是跳出loop循环
示例
let mut num = 1;
loop {
if num > 20{
break;
}
println!("num is {}",num);
num = num*3;
}
// 输出
num is 1
num is 3
num is 9
continue与break
略