Error Handling
Rust does not have exceptions. Instead, it uses:
Result<T, E>
type for recoverable errorspanic!
macro for unrecoverable errors
Panics
We can call panic!
when there is no way out of the problem.
It terminates the program.
fn main() {
panic!("fatal error");
}
Call stack
By default, when panic occurs we’ll only see the line in our code that led to
the panic. We can see the whole callstack by setting the RUST_BACKTRACE
environment
variable to anything other than 0
.
Recoverable Errors
Our functins might return Result
if there is a chance of failure.
It’s brough in by the prelude.
enum Result<T, E> {
Ok(T),
Err(E),
}
An example of a built-in API that uses Result
:
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => panic!("Problem opening the file: {:?}", error),
};
}
In this case we’re pacic!
ing when error occurs.
Methods on Result
Result
has some helper methods:
unwrap
- returns value inside ofOk
, orpanic!
s if there’s error. It’s a shortcut which can be used instead ofmatch
.expect
- likeunwrap
, but allows to specify error message for the potential panic.unwrap_or_else
- returns value inside ofOk
or executes a lambda passed to it in the case ofError
.
The ? Operator
The ?
placed after a Result
value works as follows:
- if it’s
Ok(value)
, thevalue
gets returned - if there’s an error, the containing function returns that error
?
can convert the error to the expected Error
type that a function
normally would return (theFrom
trait needs to be implemented).
Example:
fn read_username_from_file() -> Result<String, io::Error> {
let mut f = File::open("hello.txt")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
In the case above, ?
does not need to convert the error since all the expected
errors would be of type io:Error
- the same type that the function returns.