问题
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.
- Is it possible to just return an error like this?
- 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
, thenError
for it, - If there is an error, return the
Err
variant ofResult
.
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