您可以使用expect
打开带有自定义消息的Result
(在Err
上死机(。如何使用自定义消息(而不是?
的默认消息(传播错误?
use std::io::{Result, Error, ErrorKind};
fn main() -> Result<()> {
let a = Err(Error::new(ErrorKind::other, "default message"));
// Let's pretend a is a result automatically created by some other method.
let b = a.unwrap(); // panics with default message
let b = a.expect("custom message"); // panics with custom message
let b = a?; // Returns Err with default message
let b = /* What goes here? */ // Returns Err with custom message
}
有几种方法可以处理这个问题。首先,认识到没有标准";自定义错误消息";在这种情况下,因为在Result<T, E>
中,E
类型可以是任何类型,甚至是不实现std::error::Error
的类型。因此,与恐慌方法的类比并不完全成立。特别地,注意a?
不返回"0";带有默认消息的Err
"(请参阅下面的解释。(您可能想要的是一种从一种错误类型转换为另一种错误的机制。
一种方法是使用Result::map_err
,它将一个错误值映射到另一个。
struct ErrorA;
struct ErrorB;
fn foo() -> Result<(), ErrorA> { todo!() }
fn example() -> Result<(), ErrorB> {
let a = foo();
let b = a.map_err(|_| ErrorB);
b
}
但是,您可以通过实现?
操作符执行基于Into
的错误转换来自动执行此操作。表达式a?
大致相当于:
match a {
Ok(v) => v,
Err(e) => return Err(std::convert::Into::into(e)),
}
这意味着,如果存在合适的Into
impl,它将自动在错误类型之间转换。例如:
struct ErrorA;
struct ErrorB;
impl From<ErrorA> for ErrorB {
fn from(_: ErrorA) -> Self { Self }
}
fn foo() -> Result<(), ErrorA> { todo!() }
fn example() -> Result<(), ErrorB> {
let a = foo();
let b = a?; // Conversion to ErrorB is implicit
Ok(b)
}
如果你真的只想要一个";自定义字符串";则可以使用String
或&'static str
作为错误类型。不过,这在某些情况下可能会有问题,因为这两种类型都不实现std::error::Error
。然而,两者都可以转换为Box<dyn Error>
,因此,如果您不想定义自己的错误类型,可以执行以下操作:
struct ErrorA;
fn foo() -> Result<(), ErrorA> { todo!() }
fn example() -> Result<(), Box<dyn std::error::Error>> {
let a = foo();
// ? converts the &str to Box<dyn Error>
let b = a.map_err(|_| "custom error message")?;
Ok(b)
}
这种方法适用于简单的Rust程序,但通常不应在Rust库中使用。自定义错误类型更适合库,因为它们允许调用方区分不同的失败场景。
进一步阅读:
- Rust程序设计语言-使用
Result
可恢复错误