定义一个错误类型
有时候把所有不同的错误都视为一种错误类型会简化代码。我们将用一个自定义错误类型来 演示这一点。
Rust 允许我们定义自己的错误类型。一般来说,一个 “好的” 错误类型应当:
- 用同一个类型代表了多种错误
- 向用户提供了清楚的错误信息
- 能够容易地与其他类型比较
- 好的例子:
Err(EmptyVec)
- 坏的例子:
Err("Please use a vector with at least one element".to_owned())
- 好的例子:
- 能够容纳错误的具体信息
- 好的例子:
Err(BadChar(c, position))
- 坏的例子:
Err("+ cannot be used here".to_owned())
- 好的例子:
- 能够与其他错误很好地整合
use std::error;
use std::fmt;
type Result<T> = std::result::Result<T, DoubleError>;
#[derive(Debug, Clone)]
// 定义我们的错误类型,这种类型可以根据错误处理的实际情况定制。
// 我们可以完全自定义错误类型,也可以在类型中完全采用底层的错误实现,
// 也可以介于二者之间。
struct DoubleError;
// 错误的生成与它如何显示是完全没关系的。没有必要担心复杂的逻辑会导致混乱的显示。
//
// 注意我们没有储存关于错误的任何额外信息,也就是说,如果不修改我们的错误类型定义的话,
// 就无法指明是哪个字符串解析失败了。
impl fmt::Display for DoubleError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "invalid first item to double")
}
}
// 为 `DoubleError` 实现 `Error` trait,这样其他错误可以包裹这个错误类型。
impl error::Error for DoubleError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
// 泛型错误,没有记录其内部原因。
None
}
}
fn double_first(vec: Vec<&str>) -> Result<i32> {
vec.first()
// 把错误换成我们的新类型。
.ok_or(DoubleError)
.and_then(|s| {
s.parse::<i32>()
// 这里也换成新类型。
.map_err(|_| DoubleError)
.map(|i| 2 * i)
})
}
fn print(result: Result<i32>) {
match result {
Ok(n) => println!("The first doubled is {}", n),
Err(e) => println!("Error: {}", e),
}
}
fn main() {
let numbers = vec!["42", "93", "18"];
let empty = vec![];
let strings = vec!["tofu", "93", "18"];
print(double_first(numbers));
print(double_first(empty));
print(double_first(strings));
}
当前内容版权归 rust-lang-cn 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 rust-lang-cn .