实现这一点的惯用方法是定义自己的错误类型并返回它,并使用
From<T>
每种错误类型的实现
T
这可能发生在你的功能中。这个
?
接线员可以
.into()
转换以匹配函数声明返回的错误类型。
一个盒装的错误在这里太过分了;只需声明一个枚举,列出函数失败的所有方式。整数解析错误的变量甚至可以捕获捕获到的错误。
use std::fmt::{Display, Formatter, Error as FmtError};
use std::error::Error;
use std::num::ParseIntError;
#[derive(Debug, Clone)]
pub enum ExtractCodeError {
InvalidStringSize,
InvalidInteger(ParseIntError),
}
impl From<ParseIntError> for ExtractCodeError {
fn from(e: ParseIntError) -> Self {
Self::InvalidInteger(e)
}
}
impl Error for ExtractCodeError {}
impl Display for ExtractCodeError {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match self {
Self::InvalidStringSize => write!(f, "string is too short"),
Self::InvalidInteger(e) => write!(f, "invalid integer: {}", e)
}
}
}
现在我们只需要更改函数的返回类型并让它返回
ExtractCodeError::InvalidStringSize
当长度太短时。作为一个整体,没有什么需要改变的
ParseIntError
自动转换为
ExtractCodeError
:
pub fn extract_codes_as_ints(
message: String,
) -> Result<(i32, i32, i32), ExtractCodeError> {
if message.len() < 20 {
return Err(ExtractCodeError::InvalidStringSize);
}
let code1: i32 = message[0..3].trim().parse()?;
let code2: i32 = message[9..14].trim().parse()?;
let code3: i32 = message[17..20].trim().parse()?;
Ok((code1, code2, code3))
}
作为额外的好处,此函数的调用者将能够比使用盒式打印机更容易地检查错误
dyn Error
.
在更复杂的情况下,例如,对于每次可能出现的错误,您希望稍微调整错误
解释器
,你可以使用
.map_err()
在结果上转换错误。例如:
something_that_can_fail.map_err(|e| SomeOtherError::Foo(e))?;