【Fitz】Rust 流程控制
说明:本文主要是Rust语言圣经相关章节的学习笔记,大部分与其内容相同,欢迎阅读原文。
使用 if 来做分支控制
if else 表达式根据条件执行不同的代码分支,如:
if condition {
// A...
} else {
// B...
}
Rust 中的判断条件只能是布尔类型,这一点有别于C/C++。if 语句块是表达式,可以使用 if 表达式的返回值来给变量赋值。使用 if 来赋值时,需要保证每个分支返回的类型一样。
使用 else if 来处理多重条件
可以将 else if 与 if、else 组合在一起实现更复杂的条件分支判断。程序执行时,会按照自上至下的顺序执行每一个分支判断,一旦成功则跳出 if 语句块。就算有多个分支能匹配,也只有第一个匹配的分支会被执行。
对于多分支模式匹配的问题,应该使用 match 来解决,而不应该使用多个 else if 的组合。
循环控制
Rust 中有三种循环方式:for 循环、while 循环和 loop,其中 for 循环是 Rust 循环王冠上的明珠。
for 循环
for 元素 in 集合 {
// 使用元素
}
示例代码中的核心在于 for 和 in 的联动。使用 for 时我们往往使用集合的引用形式,除非不想在后面的代码中继续使用该集合。如果不使用引用的话,所有权会被转移(move)到 for 语句块中,后面就无法再使用这个集合了。
for item in &container { //使用集合的引用形式,以便后面能够继续使用该集合
// ...
}
对于实现了
copytrait 的数组(如 [i32;10])而言,for item in arr并不会把arr的所有权转移,而是直接对其进行拷贝,因此循环之后仍然可以使用arr。
按照之前的 Rust 的引用规则,想在循环中修改元素,可以使用 mut 关键字:
let mut v: Vec<String> = vec!["123".to_string(), "456".to_string()]; //使用可变引用需要声明该变量是可变的
for i in &mut v { // 这里每一个i都是 &mut String类型,即字符串的可变引用类型
// ...
}
总结:在 in 后使用 collection 会转移所有权,使用 &collection 获得的是元素的不可变引用,使用 &mut collection 获得的是元素的可变引用。
如果想要在循环中获取元素的索引,可以使用迭代器的 enumerate() 方法,该方法是一个迭代器适配器,产生一个新的迭代器:
for (i, v) in a.iter().enumerate() { // 其中i为索引,v为元素值
// ...
}
如果想用 for 循环执行某个过程 n 次但又不想单独声明一个变量控制,可以这么写:
for _ in 0..n {
// ...
}
Rust 中 _ 的含义是忽略该值或者类型的意思。
两种循环方式优劣对比
如果想要遍历访问一个数组,在使用 for 循环时,既可以通过 .. 操作符使用索引访问,也可以通过集合的方式直接循环集合中的元素。
在性能上:由于使用索引访问会进行边界检查,因此会导致运行时的性能损耗,而直接迭代访问集合元素就不会触发这种检查,因为编译器会在编译时就完成分析并证明这种访问是合法的。
在安全上:对数组的索引访问是非连续的,存在一定可能性在两次访问之间数组发生了变化,导致脏数据产生,而直接迭代是连续访问,因此没有这种风险。
for 循环无需任何条件限制,也不需要通过索引访问,因此是最安全也是最常用的。
使用 continue 可以跳过当前次的循环,开始下次的循环,使用 break 可以跳出当前整个循环,用法与 C/C++ 相同。
while 循环
当有一个条件来控制循环时,条件为 true 继续循环,条件为 false 跳出循环,那么适合使用 while 循环。
对应的功能也可以使用 loop(无条件循环) + if + break 的组合实现。
也可以使用 while 实现 for 循环的功能,但需要在 while 循环前定义一个可变变量用于循环控制。使用 while 循环容易出错(索引不正确导致 panic),也会使程序更慢(编译器增加了运行时间对每次循环的每个元素进行条件检查)。总的来说,for 循环更安全、更简洁,性能也更高。
loop 循环
loop 循环就是一个简单的无限循环,需要在内部实现逻辑并通过 break 在正确的时候跳出循环,因此在使用 loop 循环时,一定要注意。在结束 loop 循环时,break 可以单独使用,也可以带一个返回值。loop 也是一个表达式,因此可以返回一个值。

浙公网安备 33010602011771号