I noticed that Rust does not have exceptions. How to do error handling in Rust and what are the common pitfalls? Are there ways to control flow with raise, catch, reraise and other stuff? I found inconsistent information on this.
Errors are a fact of life in software, so Rust has a number of features for handling situations in which something goes wrong. In many cases, Rust requires you to acknowledge the possibility of an error and take some action before your code will compile.
To “unwrap” something in Rust is to say, “Give me the result of the computation, and if there was an error, panic and stop the program.” It would be better if we showed the code for unwrapping because it is so simple, but to do that, we will first need to explore the Option and Result types.
Rust generally solves errors in two ways:
Unrecoverable errors. Once you panic!
, that's it. Your program or thread aborts because it encounters something it can't solve and its invariants have been violated. E.g. if you find invalid sequences in what should be a UTF-8 string.
Recoverable errors. Also called failures in some documentation. Instead of panicking, you emit a Option<T>
or Result<T, E>
. In these cases, you have a choice between a valid value Some(T)
/Ok(T)
respectively or an invalid value None
/Error(E)
. Generally None
serves as a null
replacement, showing that the value is missing.
Now comes the hard part. Application.
Sometimes dealing with an Option
is a pain in the neck, and you are almost guaranteed to get a value and not an error.
In those cases it's perfectly fine to use unwrap
. unwrap
turns Some(e)
and Ok(e)
into e
, otherwise it panics. Unwrap is a tool to turn your recoverable errors into unrecoverable.
if x.is_some() { y = x.unwrap(); // perfectly safe, you just checked x is Some }
Inside the if
-block it's perfectly fine to unwrap since it should never panic because we've already checked that it is Some
with x.is_some()
.
If you're writing a library, using unwrap
is discouraged because when it panics the user cannot handle the error. Additionally, a future update may change the invariant. Imagine if the example above had if x.is_some() || always_return_true()
. The invariant would changed, and unwrap
could panic.
?
operator / try!
macroWhat's the ?
operator or the try!
macro? A short explanation is that it either returns the value inside an Ok()
or prematurely returns error.
Here is a simplified definition of what the operator or macro expand to:
macro_rules! try { ($e:expr) => (match $e { Ok(val) => val, Err(err) => return Err(err), }); }
If you use it like this:
let x = File::create("my_file.txt")?;
let x = try!(File::create("my_file.txt"));
It will convert it into this:
let x = match File::create("my_file.txt") { Ok(val) => val, Err(err) => return Err(err), };
The downside is that your functions now return Result
.
Option
and Result
have some convenience methods that allow chaining and dealing with errors in an understandable manner. Methods like and
, and_then
, or
, or_else
, ok_or
, map_err
, etc.
For example, you could have a default value in case your value is botched.
let x: Option<i32> = None; let guaranteed_value = x.or(Some(3)); //it's Some(3)
Or if you want to turn your Option
into a Result
.
let x = Some("foo"); assert_eq!(x.ok_or("No value found"), Ok("foo")); let x: Option<&str> = None; assert_eq!(x.ok_or("No value found"), Err("No value found"));
This is just a brief skim of things you can do. For more explanation, check out:
If you need to terminate some independent execution unit (a web request, a video frame processing, a GUI event, a source file to compile) but not all your application in completeness, there is a function std::panic::catch_unwind that invokes a closure, capturing the cause of an unwinding panic if one occurs.
let result = panic::catch_unwind(|| { panic!("oh no!"); }); assert!(result.is_err());
I would not grant this closure write access to any variables that could outlive it, or any other otherwise global state.
The documentation also says the function also may not be able to catch some kinds of panic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With