? 让 Rust 的错误处理简洁,但每一个细节都有规则:什么函数里才能用、错误类型怎么转换、Option 与 Result 能不能混用、main 里出错会怎样。这篇每一条规则都用编译与运行结果验证。
源码:
1 | use std::num::ParseIntError;
2 | fn parse_sum(a: &str, b: &str) -> Result<i32, ParseIntError> {
3 | println!(" 解析 a = {:?}", a);
4 | let x: i32 = a.parse()?;
5 | println!(" 解析 b = {:?}", b);
6 | let y: i32 = b.parse()?;
7 | println!(" 两个都成功,相加");
8 | Ok(x + y)
9 | }
10 | fn main() {
11 | println!("成功: {:?}", parse_sum("3", "4"));
12 | println!("第二个失败: {:?}", parse_sum("3", "x"));
13 | println!("第一个失败: {:?}", parse_sum("", "4"));
14 | }
编译:成功
运行(退出码 0):
解析 a = "3"
解析 b = "4"
两个都成功,相加
成功: Ok(7)
解析 a = "3"
解析 b = "x"
第二个失败: Err(ParseIntError { kind: InvalidDigit })
解析 a = ""
第一个失败: Err(ParseIntError { kind: Empty }) 源码:
1 | fn main() {
2 | let n: i32 = "5".parse()?;
3 | println!("{}", n);
4 | }
编译:失败
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> <实验目录>/src/u71b.rs:2:29
|
1 | fn main() {
| --------- this function should return `Result` or `Option` to accept `?`
2 | let n: i32 = "5".parse()?;
| ^ cannot use the `?` operator in a function that returns `()`
|
help: consider adding return type
|
1 ~ fn main() -> Result<(), Box<dyn std::error::Error>> {
2 | let n: i32 = "5".parse()?;
3 | println!("{}", n);
4 + Ok(())
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`. 源码:
1 | use std::num::ParseIntError;
2 | #[allow(dead_code)] #[derive(Debug)] enum MyErr { Parse(ParseIntError), Neg }
3 | fn f(s: &str) -> Result<i32, MyErr> {
4 | let n = s.parse::<i32>()?;
5 | if n < 0 { return Err(MyErr::Neg); }
6 | Ok(n)
7 | }
8 | fn main() { println!("{:?}", f("1")); }
编译:失败
error[E0277]: `?` couldn't convert the error to `MyErr`
--> <实验目录>/src/u71c.rs:4:29
|
3 | fn f(s: &str) -> Result<i32, MyErr> {
| ------------------ expected `MyErr` because of this
4 | let n = s.parse::<i32>()?;
| --------------^ the trait `From<ParseIntError>` is not implemented for `MyErr`
| |
| this can't be annotated with `?` because it has type `Result<_, ParseIntError>`
|
note: `MyErr` needs to implement `From<ParseIntError>`
--> <实验目录>/src/u71c.rs:2:38
|
2 | #[allow(dead_code)] #[derive(Debug)] enum MyErr { Parse(ParseIntError), Neg }
| ^^^^^^^^^^
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.
编译:成功
运行(退出码 0):
Ok(7)
Err(Neg)
From<ParseIntError> 被调用
Err(Parse(ParseIntError { kind: InvalidDigit }))展开成什么代码见? 运算符展开过程。
编译:成功
运行(退出码 0):
None Some(2) None
Err("空切片") Ok(9)
源码:
1 | fn f(v: &[i32]) -> Result<i32, String> {
2 | let x = v.first()?;
3 | Ok(*x)
4 | }
5 | fn main() { println!("{:?}", f(&[1])); }
编译:失败
error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
--> <实验目录>/src/u71f.rs:2:22
|
1 | fn f(v: &[i32]) -> Result<i32, String> {
| -------------------------------------- this function returns a `Result`
2 | let x = v.first()?;
| ^ use `.ok_or(...)?` to provide an error compatible with `Result<i32, String>`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.Option 与 Result 的基础见Option 与 Result。
源码:
1 | fn main() -> Result<(), std::num::ParseIntError> {
2 | println!("开始");
3 | let n: i32 = "abc".parse()?;
4 | println!("不会执行到这里 {}", n);
5 | Ok(())
6 | }
编译:成功
运行(退出码 1):
开始
Error: ParseIntError { kind: InvalidDigit }自定义错误类型的写法见自定义错误类型。