Rust 控制流结构包括:if 表达式、match 表达式和循环(loop、while、for)。
Rust 是表达式语言,程序 block 由 分号 结尾的 statement 组成。如果 expression 不以分号结尾,则它作为 block 的返回值,否则返回 unit type 值 ();
fn main() {
let x = 5u32;
let y = {
let x_squared = x * x;
let x_cube = x_squared * x;
x_cube + x_squared + x
};
// z 值是 ()
let z = {
2 * x;
};
println!("x is {:?}", x);
println!("y is {:?}", y);
println!("z is {:?}", z);
}
if-else,if-let,while-let,match,loop,block 等都是表达式,都可以用于变量赋值:
fn main() {
let n = 5;
let big_n = if n < 10 && n > -10 {
println!(", and is a small number, increase ten-fold");
10 * n
} else {
println!(", and is a big number, halve the number");
n / 2
}; // 在 let 变量赋值时,} 右边的分号不能省!
println!("{} -> {}", n, big_n);
}
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
break 10; // loop break 返回值。
}
};
循环支持嵌套,可以使用 break 'label
来跳出循环:label 的格式和 lifetime 一样,都是 ’label 格式。’label 必须位于 loop/for/while 或 { 之前:
fn main() {
'outer2: { // lable 可以位于 block { 之前
let mut count = 0;
'outer: loop {
'inner1: loop {
if count >= 20 {
break 'inner1;
}
count += 2;
}
count += 5;
'inner2: loop {
if count >= 30 {
break 'outer;
}
continue 'outer;
}
}
break 'outer2;
}
println!("Success!");
}
break 还可以返回值:
let answer = loop {
if let Some(line) = next_line() {
if line.starts_with("answer: ") {
break line;
}
} else {
break "answer: nothing";
}
};
if-let 和 while-let 支持模式匹配语法: if/while let pattern = expression {}
,pattern 中变量有效
scope 是 expression 右边的 block;
fn main() {
// pattern 的元素数量必须与右边一致,解构后的变量 scope 是表达式右边的 block;
if let (a, 1) = (2, 4) {
println!("a: {a}")
} else { // if let 不匹配的情况
println!("not match!")
}
}
// if-let 和 if 可以混合使用
let x = Some(3);
let a = if let Some(1) = x {
1
} else if x == Some(2) {
2
} else if let Some(y) = x {
y
} else {
-1
};
assert_eq!(a, 3);
// 多个 pattern 可以使用 | 分割(pattern match 的标准语法)
enum E {
X(u8),
Y(u8),
Z(u8),
}
let v = E::Y(12);
if let E::X(n) | E::Y(n) = v {
assert_eq!(n, 12);
}
match/if-let/while-let 绑定的变量只是表达式右边的 block 内部有效,一般还需要 outer let 表达式来返回值。Rust 1.65(rustc –edition=2021)开始支持 let-else 语法,let-else 的变量 scope 是所在 block:
- let-else 的 else 子句是必须的,不能返回,所以内部一般是 panic!;
use std::str::FromStr;
fn get_count_item(s: &str) -> (u64, &str) {
let mut it = s.split(' ');
// 如果匹配,count_str/item 可以在函数中使用。
let (Some(count_str), Some(item)) = (it.next(), it.next()) else {
panic!("Can't segment count item pair: '{s}'");
};
let Ok(count) = u64::from_str(count_str) else {
panic!("Can't parse integer: '{count_str}'");
};
(count, item)
}
fn main() {
assert_eq!(get_count_item("3 chairs"), (3, "chairs"));
}
// 对比,使用 match/if-let 的例子,count_str/item 只在内部有效
let (count_str, item) = match (it.next(), it.next()) {
(Some(count_str), Some(item)) => (count_str, item),
_ => panic!("Can't segment count item pair: '{s}'"),
};
// 变量析构
struct Pair(Box<i32>, Box<i32>);
impl Pair {
fn destroy(self) {
// self 的两个 Box 被转移到 first 和 second 变量,他们的 scope 是 destroy 函数体。
let Pair(first, second) = self;
println!("Destroying Pair({}, {})", first, second);
// first 和 second 在函数返回时被释放
}
}
while 用于 true/false 循环:
fn main() {
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-let 主要用于消除 loop-match 循环模式,while-let 没有 else 子句:
while let _ = 5 {
println!("Irrefutable patterns are always true");
break;
}
// loop-match 循环
let mut optional = Some(0);
loop {
match optional {
Some(i) => {
if i > 9 {
println!("Greater than 9, quit!");
optional = None;
} else {
println!("`i` is `{:?}`. Try again.", i);
optional = Some(i + 1);
}
},
_ => { break; }
}
}
// 使用简化的 while-let 语句
let mut optional = Some(0);
while let Some(i) = optional {
if i > 9 {
println!("Greater than 9, quit!");
optional = None;
} else {
println!("`i` is `{:?}`. Try again.", i);
optional = Some(i + 1);
}
}
for 专用于迭代(for-in),有三种迭代方式:
for item in collect;
item 为元素值;for item in &collect;
item 为元素值引用 &T;for item in &mut collect;
item 为元素值可变引用 &mut T;
a..b, a..=b, a..
都是 RangeXX
语法糖(a 和 b 可以是表达式), 支持 for-in 迭代和 index 操作:
fn main() {
for n in 1..=100 {
if n == 100 {
panic!("NEVER LET THIS RUN")
}
}
println!("Success!");
for number in (1..4).rev() {
println!("{}!", number);
}
}
// 范围可以是表达式
let end = 5;
let mut sum = 0;
for i in 1..(end + 1) {
sum += i;
}
对于 array 的 into_iter() , 2021 和以前的版本有所变化:
- 2021 以前版本, 如 2018,
for i in array.into_iter()
等效为for i (&array).into_iter()
, 所以迭代产生的 i 为数组元素的引用 &T; - 2021 版本以后,
for i in array.into_iter()
迭代产生的值为数组元素本身;
fn main() {
let a = [4, 3, 2, 1];
// 2021 及以后 v 类型是元素本身,以前版本是 &T;
for (i, v) in a.into_iter().enumerate() {
println!("{i} {v}");
}
}