是否有类似expect的Rust-Result方法,但它会传播错误而不是恐慌



您可以使用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)),
}

这意味着,如果存在合适的Intoimpl,它将自动在错误类型之间转换。例如:

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可恢复错误

最新更新