控制流

Rust 里的控制流与其他语言没什么差异.

if

if 的条件不带 (), 条件必须是 bool 类型.

if 是表达式，JS 三元表达式效果直接达成了:

Copy
let x = if true { 1 } else { 2 }

循环

循环控制的 loop 以前没见过，是无限循环。通过 break 和 continue 控制终止和跳过，Rust 里 break 还能返回值. break,continue 以及循环标签仨概念在 JS 的 for 里也有，就是 ES6 用习惯了没怎么接触.

标准库 Range 和 for 配合起来感觉有点意思。写 JS 循环就想过怎么没个控制循环次数的简洁方案，这下满足了.

match

match 类似 JS 里的 switch, 有严格检查确保穷尽了所有可能性。与 [[数据类型 #枚举]] 配合可以匹配提取枚举成员包含的值.

Copy
let value = match some_value {
Some(i) => i,
None => 0
}

可以使用通配符 other (还以为 other 是个关键字) 或 _ 对其他场景做处理，通配符按常理应该写在最后一个条件，否则会导致其后写的条件完全无效.

Copy
match some_num {
1 => call(),
3 => check(),
other => println!("{}", other),
// 也可以用 _ 不获取剩余情况的具体值
// _ => (),
}

if let

只需处理一种情况的场景，使用 if let 语法更简洁，但比 match 少了穷尽检查.

Copy
if let Some(value) = some_value {
println!("{}", value);
}

? 运算符

类似 JS 中的可选链, 可作用于 Option 和 Result 传播错误或 None 值。只能写在返回值兼容的函数体内，比如要对 Result 使用 ? 必须返回 Result. 有一点不同是对 Result 可以在函数体任何位置使用，这样做会提前中断并返回 Result::Err.

模式匹配

模式 是 Rust 中用来匹配类型结构的语法。有点像 JS 的解构赋值, 理解起来有点反逻辑思路，但可使用的场景更多，控制流大部分都能用模式匹配.

let 语句可以模式匹配，= 左侧的模式匹配右侧表达式，match 分支里的 => 左侧模式匹配 match 关键字右侧表达式，if let 语句 = 左侧模式匹配右侧表达式.

Copy
let (x, y) = (1, 2);

match some_value {
Some(4) | Some(5) => {},
Some(x) => {},
None => {}
}

if let 1..=3 = some_value {
} else if is_true{
} else {
}

// 解构结构体
let User { name: username, age } = user;

这么看 if let 有点像 if (模式匹配结果) 句型.

可反驳性

如果表达式存在不能匹配模式的可能，则这个模式是可反驳的，比如 match 里的分支条件。反之为不可反驳的模式。也可以说穷尽所有可能性的情况下是不可反驳的. let 和 for 只接受不可反驳模式.

忽略模式中的值

使用 _ 忽略单个值，可以在一个模式中重复使用；

使用 .. 忽略剩余值，但必须保证被忽略的部分没有歧义；

匹配守卫

在 match 的分支条件后可以用 if 关键字添加守卫，即额外的匹配条件.

Copy
match some_value {
Some(1) | Some(2) => {},
Some(v) if v > 0 => {},
Some(_) => {},
_ => {}
}

添加的 if 作用于前面的整个模式，如果同时使用了 | 运算符指定了多个模式，if 前的优先级更高。以后八成会被这个坑到.

Copy
match x {
// 这里无论 x 是几都不会匹配
1 | 2 | 3 if false => {},
_ => {}
}

如果希望同时获取变量并匹配模式，可以使用 @ 绑定.

Copy
match user {
// 这里的 age 被用来匹配了, 后面的块中无法访问 age 值
User { age: 1..=18, .. } => {},
// 这样就可以用了
User { age: user_age @ 20..=35, .. } => {}
}