我有一个自定义错误枚举,它包含了我代码中的几个常见错误:
pub enum ParseError {
Io(io::Error),
Parse(serde_json::error::Error),
FileNotFound(PathBuf, io::Error),
}
此枚举实现了 Display 特性(按要求):
impl Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ParseError::Io(io_error) => write!(f, "{}", io_error),
ParseError::Parse(parse_error) => write!(f, "{}", parse_error),
ParseError::FileNotFound(file, err) => {
write!(f, "Could not open file {}: {}", file.to_string_lossy(), err)
}
}
}
}
注意,对于“自定义错误”FileNotFound,我需要写!错误和它附带的文件名。但是,稍后当我处理这个错误时,我需要再次打印文件名和错误:
match my_function(arg1, arg2) {
Ok(_) => (),
Err(error) => match error {
Io(err) => //do stuff,
},
Parse(err) => //do stuff
},
FileNotFound(file, err) => {
println!("Can't find file '{}': {}", file.to_string_lossy(), err)
}
没有格式化文件名和匹配中的错误,Rust 只是打印一般错误(在这种情况下“系统找不到指定的文件。(操作系统错误 2)”。
我的问题是:为什么需要先实现显示和格式化错误,如果需要再次格式化才能打印/使用它?
不需要重新格式化。当您不使用
match
时,这特别有用,但是当您这样做时,您可以使用 @
创建对整个项目的绑定:
match my_function(arg1, arg2) {
Ok(_) => (),
Err(error) => match error {
Io(err) => { //do stuff,
}
Parse(err) => { //do stuff
}
error @ FileNotFound(..) => {
println!("{error}");
}
},
}
您还可以就地构建错误:
FileNotFound(file, err) => {
println!("{}", FileNotFound(file, err));
}
另一个常见的事情是使用 catch-all 对所有不匹配的错误执行操作:
error => {
println!("{error}");
}