Rust正确的错误处理(从一种错误类型自动转换为带问号的另一种错误类型)

S.R*_*S.R 15 rust

我想学习如何正确处理Rust中的错误.我读过这本书这个例子 ; 现在我想知道我应该如何处理这个函数中的错误:

fn get_synch_point(&self) -> Result<pv::synch::MeasPeriods, reqwest::Error> {
    let url = self.root.join("/term/pv/synch"); // self.root is url::Url
    let url = match url {
        Ok(url) => url,
        // ** this err here is url::ParseError and can be converted to Error::Kind https://docs.rs/reqwest/0.8.3/src/reqwest/error.rs.html#54-57 **//
        Err(err) => {
            return Err(Error {
                kind: ::std::convert::From::from(err),
                url: url.ok(),
            })
        }
    };

    Ok(reqwest::get(url)?.json()?) //this return reqwest::Error or convert to pv::sych::MeasPeriods automaticly
}      
Run Code Online (Sandbox Code Playgroud)

这段代码不合适; 它会导致编译错误:

error[E0451]: field `kind` of struct `reqwest::Error` is private
  --> src/main.rs:34:42
   |
34 |             Err(err) => return Err(Error{kind: ::std::convert::From::from(err), url: url.ok()})
   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `kind` is private

error[E0451]: field `url` of struct `reqwest::Error` is private
  --> src/main.rs:34:81
   |
34 |             Err(err) => return Err(Error{kind: ::std::convert::From::from(err), url: url.ok()})
   |                                                                                 ^^^^^^^^^^^^^ field `url` is private
Run Code Online (Sandbox Code Playgroud)

处理这种情况的正确模式是什么?对我来说,reqwest::Error在这种情况下是一个很好的解决方案,所以我想避免定义我自己的错误类型:

enum MyError {
    Request(reqwest::Error),
    Url(url::ParseError) // this already a part of request::Error::Kind!!!
} 
Run Code Online (Sandbox Code Playgroud)

S.R*_*S.R 27

2020 年更新

Rust 编程语言正在快速发展,因此可以添加新的答案!我真的很喜欢custom_error但现在我认为这thiserror将是我所爱的人!

use thiserror::Error;

#[derive(Error, Debug)]
pub enum DataStoreError {
    #[error("data store disconnected")]
    Disconnect(#[from] io::Error),
    #[error("the data for key `{0}` is not available")]
    Redaction(String),
    #[error("invalid header (expected {expected:?}, found {found:?})")]
    InvalidHeader {
        expected: String,
        found: String,
    },
    #[error("unknown data store error")]
    Unknown,
}
Run Code Online (Sandbox Code Playgroud)

这允许更改io::ErrorDataStoreError::Disconnect带问号?。去这里了解详情

有用的链接:


其他有趣的板条箱:

  • 无论如何- 建立在 std::error::Error 上的灵活的具体错误类型
  • snafu - Situation Normal: All Fouled Up - SNAFU 是一个库,可以在添加上下文的同时轻松地将底层错误分配到特定于域的错误中。(类似于这个错误)
  • custom_error - 此 crate 包含一个,可以更轻松地定义自定义错误,而无需编写大量样板代码。

对于恐慌:


Vla*_*eev 16

不幸的是,在您的情况下reqwest::Error,如果reqwest库没有提供这样做的方法(并且可能没有),则无法从其他错误类型创建.要解决此问题,这是非常常见的,特别是在使用多个库的应用程序中,正确的解决方案将是以下之一:

  1. 使用应用程序使用的所有错误(或应用程序的一个子系统;粒度高度依赖于项目)声明您自己的自定义枚举,并声明From从您使用的所有错误到此枚举类型的转换.

    作为此方法的扩展,您可以使用error-chain(或quick-error基于错误链的基础)以半自动方式生成此类自定义类型和转换.

  2. 使用特殊的通用错误类型.基本上有两个:

    一个.Box<Error>Error标准库中定义的位置.

    湾 使用包中Error定义的类型failure.

    然后问号运算符将能够将任何兼容的错误转换为这些类型之一,因为各种IntoFrom特征实现.

请注意,failure箱子旨在定义在锈社区推广的错误方式.它不仅提供了一个常见的错误类型和特征(它修复了std::error::Error特征的各种问题;例如参见此处),它还具有定义您自己的错误类型的工具(例如,使用failure_derive),以及跟踪错误上下文,原因并生成回溯.此外,它会尝试与现有的错误处理方法尽可能兼容,因此它可以用来与使用其他,较旧的方法(库集成std::error::Error,error-chain,quick-error)很容易.所以我强烈建议你先考虑使用这个箱子,然后再考虑其他选择.

我已经开始failure在我的应用程序项目中使用,而我无法表达错误处理变得更容易和更好.我的方法如下:

  1. 定义Result类型:

    type Result<T> = std::result::Result<T, failure::Error>;
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用Result<Something>无处不在可以返回一个错误,使用问号运算符(?)错误和功能之间的转换像err_msgformat_err!bail!创建自己的错误消息.

我还没有使用编写库failure,但我想对于库来说,创建更多特定的错误声明为枚举是很重要的,这可以通过failure_derivecrate 来完成.但是对于应用程序来说,failure::Error类型绰绰有余.

  • 失败箱已被弃用 https://github.com/rust-lang-nursery/failure/pull/347 (2认同)

lov*_*soa 5

在这种情况下,无法重用基础错误类型,因为您无法构造其隐藏字段。即使有可能,我也会建议不要这样做,以便使您的代码更加灵活且面向未来。

定义自定义错误类型可能需要编写大量样板文件,但幸运的是,有几个库可以减轻这种痛苦。上面已经提到了failureerror-chainfast-error,但我想向您指出我写的一个板条箱,它比其他板条箱涉及更少的样板:custom_error。有了它,你可以写:

#[macro_use] extern crate custom_error;

custom_error!{ MyError
    Request{source: reqwest::Error} = "request error",
    Url{source: url::ParseError}    = "invalid url"
}
Run Code Online (Sandbox Code Playgroud)