Correct Rust error handling (automatic conversion from one type of error to another with a question mark)

I want to learn how to properly deal with errors in Rust. I read a book and this example ; Now I would like to know how I should fix errors in this function:

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
}      

this code is incorrect; this causes a compilation error:

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

What is the correct procedure in this case? For me reqwest::Error, this is a good solution, so I would like to avoid defining my own type of error:

enum MyError {
    Request(reqwest::Error),
    Url(url::ParseError) // this already a part of request::Error::Kind!!!
} 
+14
source share
4 answers

, . , , .

, , , , . , , , , , : custom_error. :

#[macro_use] extern crate custom_error;

custom_error!{ MyError
    Request{source: reqwest::Error} = "request error",
    Url{source: url::ParseError}    = "invalid url"
}
+4

, reqwest::Error , reqwest (, , ). , , , , :

  1. , ( ; ), From , , .

    error-chain ( quick-error, ) - .

  2. . :

    . Box<Error> Error .

    . Error, failure.

    - Into From.

, failure , Rust. ( std::error::Error; ., , ), (, failure_derive), , . , , , , (std::error::Error, error-chain, quick-error). , .

failure , , . :

  1. Result:

    type Result<T> = std::result::Result<T, failure::Error>;
    
  2. Result<Something> , , (?) , err_msg format_err! bail! .

failure, , , enum, failure_derive. , , failure::Error .

+15

As already mentioned, Vladimir Matveev , the failure of the box should be the starting point. Here is my solution:

use std::io;
use std::result;

use failure::{Backtrace, Fail};

/// This is a new error type manged by Oxide library.
/// The custom derive for Fail derives an impl of both Fail and Display.
#[derive(Debug, Fail)]
pub enum OxideError {
    #[fail(display = "{}", message)]
    GeneralError { message: String },

    #[fail(display = "{}", message)]
    IoError {
        message: String,
        backtrace: Backtrace,
        #[cause]
        cause: io::Error,
    },
}

/// Create general error
pub fn general(fault: &str) -> OxideError {
    OxideError::GeneralError {
        message: String::from(fault),
    }
}

/// Create I/O error with cause and backtrace
pub fn io(fault: &str, error: io::Error) -> OxideError {
    OxideError::IoError {
        message: String::from(fault),
        backtrace: Backtrace::new(),
        cause: error,
    }
}

This error listing is extensible for future needs.

0
source

Update 10.10.2019

Rust develops quickly, so you can add a new answer! I really like custom_error , but I think this box will now be my favorite person!

use thiserror::Error;

#[derive(Error, Debug)]
pub enum DataStoreError {
    #[error("data store disconnected")]
    Disconnect(#[source] 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,
}

This allows you to change io::Errorto DataStoreError::Disconnecta question mark ?.

Sources: crates.io or GitHub

0
source

Source: https://habr.com/ru/post/1692666/


All Articles