How to manually return a Result<(), Box<dyn Error>>?

こ雲淡風輕ζ 提交于 2020-01-12 03:39:45

问题


I want to return an error from a function in case a condition is true:

use std::error::Error;

pub fn run() -> Result<(), Box<dyn Error>> {
    // -- snip ---

    if condition {
        // return error
    }

    // -- snip --

    Ok(())
}

fn main() {}

I probably don't have the basics of the typesystem down, but everywhere I looked people use the ? operator, so I can't figure out what type to return.

  1. Is it possible to just return an error like this?
  2. Is there a better way to handle this logic?

回答1:


Error is a trait and you want to return a trait object (note the dyn keyword), so you need to implement this trait:

use std::error::Error;
use std::fmt;

#[derive(Debug)]
struct MyError(String);

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "There is an error: {}", self.0)
    }
}

impl Error for MyError {}

pub fn run() -> Result<(), Box<dyn Error>> {
    let condition = true;

    if condition {
        return Result::Err(Box::new(MyError("Oops".into())));
    }

    Ok(())
}

fn main() {
    if let Err(e) = run() {
        println!("{}", e); // "There is an error: Oops"
    }
}
  • Create your own error type,
  • Implement Debug, Display, then Error for it,
  • If there is an error, return the Err variant of Result.

I advise you to use failure that remove all the error boilerplate:

#[derive(Fail, Debug)]
#[fail(display = "There is an error: {}.", _0)]
struct MyError(String);

--

Note that if you expect an Error, you can return whatever type you want, given that it implements Error. This includes the error types in std.




回答2:


I am new to Rust, but here is my dirty hack to return custom errors, given that the function is set to return Result<(), Box<dyn Error>>:

fn serve(config: &Config, stream: TcpStream) -> Result<(), Box<dyn Error>> {
    // ...
    if request_is_bad() {
        // This returns immediately a custom "Bad request" error
        Err("Bad request")?;
    }
    // ...
}



回答3:


A Result<T, E> is an enum with two variants. To return either of them, you just use corresponding variants.

fn foo(var: bool) -> Result<(), i32> {
    if var {
        Ok(()) //in fact this is std::result::Result::Ok
    } else {
        Err(-3) //in fact this is std::result::Result::Err
    }
}

The reason why you don't have to write std::result::Result::Ok is that it is in the prelude. As you can see, you don't have to stick to Box<Error>, but can return any type you want. It is a generic enum, with no restrictions.

The ?-operator is a handy shortcut for early returns, so you don't have to be too verbose about results.



来源:https://stackoverflow.com/questions/51550167/how-to-manually-return-a-result-boxdyn-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!