# Error Handling
Rust does not have exceptions. Instead, it uses:
Result<T, E>
type for recoverable errorspanic!
macro for unrecoverable errors
.NET Analogy
panic!
s are like unhandled exceptions in .NET, while Result
allows us
to act similarly to try-catch
in .NET.
# Panics
We can call panic!
when there is no way out of the problem.
It terminates the program.
fn main() {
panic!("fatal error");
}
Unwind or abort
When a panic occurs Rust unwinds the stack - cleans data from all stack frames. It takes time. We can set our app to just abruptly abort execution in case of panic (in the TOML file).
# 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
WARNING
?
can only be used in functions that return Result
or Option
,
or any type that implements Try
.
?
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)
}
TIP
It could be even shorter with chaining calls:
fn read_username_from_file() -> Result<String, io::Error> {
let mut s = String::new();
File::open("hello.txt")?.read_to_string(&mut s)?;
Ok(s)
}
or even:
fn read_username_from_file() -> Result<String, io::Error> {
fs::read_to_string("hello.txt")
}
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.
← Collections Generics →