文章目录
- 1.核心区别
- 2.示例对比
- match
- if let
- ?
- 3.如何选择?
- 4.一句话总结
- 参考文献
if let、match和?都是 Rust 中处理Result/Option的方式,但适用场景完全不同。1.核心区别
| 写法 | 关注点 | 适用场景 | 是否穷尽 |
|---|---|---|---|
match | 所有分支 | 需要同时处理Ok和Err(或Some和None) | ✅ 必须穷尽 |
if let | 一种分支 | 只关心其中一种情况,另一种忽略 | ❌ 不要求 |
? | 错误传播 | 错误直接向上返回,不处理 | — |
2.示例对比
假设有一个返回Result<i32, String>的函数:
fnget_value()->Result<i32,String>{// ...}match
match 是 Rust 模式匹配的基础语法,其他两者都是它的语法糖。它要求穷尽所有分支。
matchget_value(){Ok(v)=>println!("成功: {}",v),Err(e)=>println!("失败: {}",e),}if let
if let:只关心一种情况,是 match 的语法糖。
// 只关心成功ifletOk(v)=get_value(){println!("成功: {}",v);}// 只关心失败ifletErr(e)=get_value(){println!("失败: {}",e);}等价于:
// 只关心成功matchget_value(){Ok(v)=>{println!("成功: {}",v);}_=>{}// Err 分支什么都不做}// 只关心失败matchget_value(){Err(e)=>{println!("失败: {}",e);}_=>{}// Ok 分支什么都不做}?
?表示错误直接向上传播,用于成功时解包,失败时提前返回,也是 match 的语法糖。
fnprocess()->Result<i32,String>{letv=get_value()?;// 如果是 Err,直接返回;如果是 Ok,解包出 vOk(v*2)}等价于:
fnprocess()->Result<i32,String>{letv=matchget_value(){Ok(v)=>v,Err(e)=>returnErr(e.into()),// 自动调用 .into() 做错误类型转换};Ok(v*2)}为什么是 e.into()?
因为 ? 支持错误类型自动转换。比如你的函数返回 MyError,但 expr 返回的是io::Error,只要实现了From<io::Error> for MyError,? 就会自动帮你转换。
// 没有 ? 时,你需要手动转换letv=matchexpr{Ok(v)=>v,Err(e)=>returnErr(MyError::from(e)),// 手动转换};// 有了 ?,编译器自动帮你做letv=expr?;对 Option:
// 你写的代码letv=expr?;// 等价 matchletv=matchexpr{Some(v)=>v,None=>returnNone,};3.如何选择?
| 场景 | 推荐写法 |
|---|---|
| 需要分别处理成功和失败,逻辑不同 | match |
| 只关心成功,失败时什么都不做 | if let Ok(v) |
| 只关心失败,成功时什么都不做 | if let Err(e) |
| 错误不需要处理,直接向上抛 | ? |
| 需要同时处理多个条件分支 | match或if let ... else if let |
4.一句话总结
match处理所有分支,if let只关心一种分支,?把错误直接向上抛。需要穷尽处理用match,只关心一种情况用if let,错误直接传播用?。
参考文献
Rust 程序设计语言 - 枚举和模式匹配
模式和匹配- Rust 程序设计语言中文版