内容节选自专栏文章:Rust 11:错误处理(Option<T>、Result<T,E>、panic、catch_unwind)
Rust编程中主要通过Option<T>
和Result<T,E>
来传播和处理各种错误。
?操作符
为了让Result<T,E>类型的处理更加方便简洁,Rust中引入了?
操作符。
问号操作符是针对Result<T,E>
类型的一个语法糖,?操作符内部被展开成一段类似如下match匹配的代码:
match result {
Ok(v) => v,
Err(e) => return Err(e.into())
}
- 如果
Result
是一个E类型
的错误值,则提前返回错误,结束当前函数。 - 如果
Result
是一个T类型
的正确值,则提取出值,方便后续进行链式调用。
所以,?操作符
可以方便地对Result<T,E>
进行值提取(Ok(v) => v
),或者返回一个错误类型值,提前结束当前函数。
代码测试
先来定义一个自己的错误类型:
struct MyError {
code: i32,
msg: String
}
use std::fmt::{Display,Debug,Formatter};
impl std::error::Error for MyError { }
impl Debug for MyError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}]{}", self.code, self.msg)
}
}
impl Display for MyError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "[{}]{}", self.code, self.msg)
}
}
在main()
函数中测试:
fn main() -> Result<(), MyError> {
let oneError: Result<(), MyError>= Err(MyError{
code: -1,
msg: "error".to_owned(),
});
// 问号操作符是针对Result<T,E>类型的一个语法糖
// 本质是一个match匹配
// 如果Result是一个E类型的错误值,则提前返回错误,结束当前函数
// 如果Result是一个T类型的正确值,则提取出值,方便后续进行链式调用
oneError?;
Ok(())
}
限制!!
/// the `?` operator can only be used in a function that returns `Result`
/// or `Option` (or another type that implements `FromResidual`)
- ?操作符只能使用在以Option或者Result作为返回值的函数体中。
- 如果要在main()中使用?操作符。那么首先是要求main()返回值是Option或者Result类型(满足第一条);其次,还要求返回值是要实现
std::process::Termination trait
的类型。
rust文档:Termination
pub trait Termination {
fn report(self) -> i32;
}
其中report()
方法返回一个i32
值,这与C语言中main()
函数要求返回一个整数值一致。
测试代码中的Result<(), MyError>
可以作为main函数的返回值类型,是因为标准库中有如下实现:
impl<E: fmt::Debug> Termination for Result<(), E> {
fn report(self) -> i32 {
match self {
Ok(()) => ().report(),
Err(err) => Err::<!, _>(err).report(),
}
}
}