? 只有一个字符,背后是什么?这篇不靠背诵,而是让编译器打印出 HIR,再手写等价的 match 对比,最后验证闭包里的 ? 与 Box
源码:
pub fn double(s: &str) -> Result<i32, std::num::ParseIntError> {
let n: i32 = s.parse()?;
Ok(n * 2)
}
HIR:
fn double(s: &'_ str)
->
Result<i32,
std::num::ParseIntError> {
let n: i32 =
match branch(s.parse()) {
Break { 0: residual } => #[allow(unreachable_code)]
return from_residual(residual),
Continue { 0: val } => #[allow(unreachable_code)]
val,
};
Ok(n * 2)
}? 的使用规则见Result 错误传播。展开使用 RUSTC_BOOTSTRAP=1,输出格式随编译器版本变化。
源码:
pub fn first_plus(v: &[i32]) -> Option<i32> {
let f = v.first()?;
Some(*f + 1)
}
HIR:
fn first_plus(v: &'_ [i32])
->
Option<i32> {
let f =
match branch(v.first()) {
Break { 0: residual } => #[allow(unreachable_code)]
return from_residual(residual),
Continue { 0: val } => #[allow(unreachable_code)]
val,
};
Some(*f + 1)
} 源码:
1 | #[allow(dead_code)] #[derive(Debug)] struct E(String);
2 | impl From<std::num::ParseIntError> for E { fn from(e: std::num::ParseIntError) -> E { println!(" From 转换"); E(e.to_string()) } }
3 | fn with_q(s: &str) -> Result<i32, E> { let n: i32 = s.parse::<i32>()?; Ok(n + 1) }
4 | fn manual(s: &str) -> Result<i32, E> {
5 | let n = match s.parse::<i32>() { Ok(v) => v, Err(e) => return Err(From::from(e)) };
6 | Ok(n + 1)
7 | }
8 | fn main() {
9 | for s in ["41", "zz"] { println!("? 版本 {:?} -> {:?}", s, with_q(s)); println!("手写版本 {:?} -> {:?}", s, manual(s)); }
10 | }
编译:成功
运行(退出码 0):
? 版本 "41" -> Ok(42)
手写版本 "41" -> Ok(42)
From 转换
? 版本 "zz" -> Err(E("invalid digit found in string"))
From 转换
手写版本 "zz" -> Err(E("invalid digit found in string")) 编译:成功
运行(退出码 0):
闭包里 ? 失败: Err(ParseIntError { kind: InvalidDigit })
outer 继续往下执行
outer 返回 7 编译:成功
运行(退出码 0):
"5" -> Ok(5)
"x" -> Err(invalid digit found in string)
"-1" -> Err(负数不允许)自定义错误类型见自定义错误类型。