Error handling in Rust is actually pretty awesome. There's a standard `Result<T, E>` type. One can write a potentially fail-able function like: fn can_fail(arg: bool) -> Result<(), StrBuf> {
if arg {
Ok(())
} else {
Err(StrBuf::from_str("Oops! Something went wrong."))
}
}
Here, there's no value when the function succeeds `()`. When it fails (I don't mean fail as in a `fail!()` or a panic or anything), you get a string back.You can pattern match the return value: match can_fail(true) {
Ok(_) => {},
Err(err) => {}
}
This can get quite cumbersome, however. That's why there's a `try!` macro that adds composability. The idea is that if you have a function returning a `Result`, wherever that function is being called could also return a `Result`. fn higher_up() -> Result<(), StrBuf> {
try!(can_fail(true));
}
`try!` is simply: match $e { Ok(e) => e, Err(e) => return Err(e) }
This allows error to propagate up the chain.When you're working in big-ish projects, it'd be best to have something better than a simple `StrBuf` for an error. You'd probably want a struct: pub struct LibError {
message: StrBuf,
error: Error
}
pub enum Error {
One,
Two,
Three
}
Where `Lib` is the library/project name.You can then create a new result type based on your new error type: type LibResult<T> = Result<T, LibError>;
Then you can use `LibResult<T>` everywhere in your app.You can view this example done in a few of my own libraries (https://github.com/TheHydroImpulse/gossip.rs/blob/master/src...) and cargo (https://github.com/carlhuda/cargo/blob/master/src/cargo/util...). That's a simple overview of it. Error handling is super simple, not verbose (thanks to try!) and in your control. Because of Rust's type system, things like `Result<T, E>` is available and are so much better than simple return values (like integers: -1 vs 0 uhhh) |