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.