Kurtis Nusbaum
Kurtis Nusbaum

Reputation: 30845

Convert Result in place

I have the following code:

/// An error that encapsulates all possible configuration errors.
#[derive(Debug)]
pub enum Error {
    /// An error that occured while parsing a yaml configuration.
    Yaml(serde_yaml::Error),
}

impl From<serde_yaml::Error> for Error {
    fn from(err: serde_yaml::Error) -> Error {
        Error::Yaml(err)
    }
}

/// A `Result` type alias for this config module's `Error` type.
pub type Result<T> = ::std::result::Result<T, Error>;

pub fn new(mut args: env::Args) -> Result<Config, Error> {
    // initialize config_file variable
    let config = serde_yaml::from_reader(config_file)?;
    Ok(config)
}

serde_yaml::from_reader returns a serde_yaml::Result which uses serde_yaml::Error for the Result's error type. The code above compiles just fine.

That said, it seems a little funny that I should have to unwrap the Result given back to me from calling serde_yaml::from_reader only to then immediately repackage in into a new Ok. In other words, I'd really like to be able to just write:

pub fn new(mut args: env::Args) -> Result<Config> {
    // initialize config_file variable
    serde_yaml::from_reader(config_file)
}

But when I try to do this, I get the following compiler error:

error[E0308]: mismatched types
  --> src/config.rs:28:9
   |
18 |     pub fn new(mut args: env::Args) -> Result<Config> {
   |                                        -------------- expected `std::result::Result<config::Config, config::Error>` because of return type
...
28 |         serde_yaml::from_reader(config_file)
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `config::Error`, found struct `serde_yaml::Error`
   |
   = note: expected type `std::result::Result<config::Config, config::Error>`
              found type `std::result::Result<_, serde_yaml::Error>`

What's going on here and what's the most idiomatic thing to do in this situation? Should I just leave my code as is?

Upvotes: 2

Views: 5202

Answers (1)

DK.
DK.

Reputation: 59145

You have two different error types. Different types aren't compatible. There's nothing more to it than that.

It's worth noting that you're not just "re-wrapping" the value; you're pulling the initial Result value apart, doing a conversion of the error type, branching out of the function if there was an error, then re-wrapping the value into a different Result type. Also, you don't even need the variable there; you could equally write it as Ok(serde_yaml::from_reader(config_file)?).

If you really don't want to use ? and Ok, you can do the error conversion another way:

serde_yaml::from_reader(config_file)
    .map_err(|e| e.into())

But that's essentially the same thing, sans the "early return on error" part.

Upvotes: 7

Related Questions