Rust 里的控制流与其他语言没什么差异.
if#
if
的条件不带 ()
, 条件必须是 bool
类型.
if
是表达式,JS 三元表达式效果直接达成了:
let x = if true { 1 } else { 2 }
循环#
循环控制的 loop
以前没见过,是无限循环。通过 break
和 continue
控制终止和跳过,Rust 里 break 还能返回值. break,continue 以及循环标签仨概念在 JS 的 for
里也有,就是 ES6 用习惯了没怎么接触.
标准库 Range 和 for
配合起来感觉有点意思。写 JS 循环就想过怎么没个控制循环次数的简洁方案,这下满足了.
match#
match
类似 JS 里的 switch
, 有严格检查确保穷尽了所有可能性。与 [[数据类型 #枚举]] 配合可以匹配提取枚举成员包含的值.
let value = match some_value {
Some(i) => i,
None => 0
}
可以使用通配符 (还以为 other 是个关键字) 或 other
_
对其他场景做处理,通配符按常理应该写在最后一个条件,否则会导致其后写的条件完全无效.
match some_num {
1 => call(),
3 => check(),
other => println!("{}", other),
// 也可以用 _ 不获取剩余情况的具体值
// _ => (),
}
if let#
只需处理一种情况的场景,使用 if let
语法更简洁,但比 match
少了穷尽检查.
if let Some(value) = some_value {
println!("{}", value);
}
? 运算符#
类似 JS 中的可选链, 可作用于 Option
和 Result
传播错误或 None 值。只能写在返回值兼容的函数体内,比如要对 Result 使用 ?
必须返回 Result. 有一点不同是对 Result 可以在函数体任何位置使用,这样做会提前中断并返回 Result::Err
.
模式匹配#
模式 是 Rust 中用来匹配类型结构的语法。有点像 JS 的解构赋值, 理解起来有点反逻辑思路,但可使用的场景更多,控制流大部分都能用模式匹配.
let
语句可以模式匹配,=
左侧的模式匹配右侧表达式,match 分支里的 =>
左侧模式匹配 match
关键字右侧表达式,if let
语句 =
左侧模式匹配右侧表达式.
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
关键字添加守卫,即额外的匹配条件.
match some_value {
Some(1) | Some(2) => {},
Some(v) if v > 0 => {},
Some(_) => {},
_ => {}
}
添加的 if
作用于前面的整个模式,如果同时使用了 |
运算符指定了多个模式,if
前的优先级更高。以后八成会被这个坑到.
match x {
// 这里无论 x 是几都不会匹配
1 | 2 | 3 if false => {},
_ => {}
}
如果希望同时获取变量并匹配模式,可以使用 @
绑定.
match user {
// 这里的 age 被用来匹配了, 后面的块中无法访问 age 值
User { age: 1..=18, .. } => {},
// 这样就可以用了
User { age: user_age @ 20..=35, .. } => {}
}