We all know that rust doesn't have a try function. In python, there's only one and know as the best way to handle specific error types:
try:
# do something that may fail
except IDontLikeYouException:
# say please
except YouAreTooShortException:
# stand on a ladder
But how can we do it in rust? I know we can do something like:
(inside a match)
Ok(x) => { },
Err(e) => match e.kind() {
Error => break,
AnotherError => do_something(),
_ => panic!("..."),
},
But I feel confused as there's not a way that is seen by the community as a pattern, and if it does, I don't know, and that's what I'm looking for here. Does anyone know what would be the most accepted code for that?
Matching is definitely the best way to take different actions when different errors occur. For more on error handling see:
https://doc.rust-lang.org/book/ch09-00-error-handling.html
https://doc.rust-lang.org/rust-by-example/error.html
1 Like
In the common case of:
let foo = match fallible_call() {
Ok(x) => x,
Err(e) => return Err(e)
};
There's shorthand in the form of ?
, where expr?
expands to
match expr {
Ok(x) => x,
Err(e) => return Err(e.into())
}
You may be looking for something like this, where the error type is an enum
of all possible sub-errors. In this case a match statement is quite natural
enum MyError {
IDontLikeYouException,
YouAreTooShortException,
}
use MyError::*;
fn something_that_may_fail(x: u8) -> Result<(), MyError> {
match x {
0 => Err(IDontLikeYouException),
_ => Err(YouAreTooShortException),
}
}
fn main() {
match something_that_may_fail(1) {
Ok(()) => println!("how did this succeed"),
Err(IDontLikeYouException) => println!("I don't like you"),
Err(YouAreTooShortException) => println!("You are too short"),
}
}
Alternatively if you're dealing with dynamic error types, you can try downcasting to get the underlying type. In this case, the function needs to return something like Result<T, Box<dyn std::error::Error>>
. This is a bit closer to Python exceptions, but in Rust the first style is obviously better if you know all your Error types beforehand.
// define IDontLikeYouException and YouAreTooShortException
// as structs implementing std::error::Error
fn something_that_may_fail(x: u8) -> Result<(), Box<dyn std::error::Error>> {
match x {
0 => Err(Box::new(IDontLikeYouException{})),
_ => Err(Box::new(YouAreTooShortException{})),
}
}
fn main() {
match something_that_may_fail(0) {
Ok(()) => println!("how did this succeed"),
Err(e) => {
if let Some(_) = e.downcast_ref::<IDontLikeYouException>() {
println!("I don't like you");
} else if let Some(_) = e.downcast_ref::<YouAreTooShortException>() {
println!("You are too short");
} else {
println!("Unknown error");
}
}
}
}
1 Like