handling errors in rust
This commit is contained in:
parent
c21100a102
commit
2b837a207d
100
content/posts/2022.04.13.handling-errors-in-rust.md
Normal file
100
content/posts/2022.04.13.handling-errors-in-rust.md
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
---
|
||||||
|
title: "Handling Errors in Rust"
|
||||||
|
date: 2022-04-13T15:31:11-04:00
|
||||||
|
toc: false
|
||||||
|
images:
|
||||||
|
tags:
|
||||||
|
- dev
|
||||||
|
- rust
|
||||||
|
---
|
||||||
|
|
||||||
|
Rust uses a pretty interesting way to deal with errors. Languages like Python
|
||||||
|
and JavaScript allow you to throw errors completely unchecked. C does error
|
||||||
|
handling through the `errno` which is also completely unchecked and not enforced
|
||||||
|
in any way by the programming language. This means any function you call may
|
||||||
|
throw an error, and other than documentation there's nothing to let you know
|
||||||
|
that it might do so.
|
||||||
|
|
||||||
|
Worse, most of these languages don't tell you what kind of error a function
|
||||||
|
might throw. That's obvious in JavaScript, and TypeScript doesn't help with it
|
||||||
|
either (errors caught have `any` or `unknown` type). C++ and Python let you
|
||||||
|
catch specific types of errors, but you have to rely on documentation to know
|
||||||
|
which types those are.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
try {
|
||||||
|
// ...
|
||||||
|
} catch (err: any) {
|
||||||
|
// Is it a file error? Did I access something undefined? Who knows.
|
||||||
|
```
|
||||||
|
|
||||||
|
Java, on the other hand, requires you to explicitly mark what errors a function
|
||||||
|
can throw and enforces that you handle all the errors or explicitly mark that
|
||||||
|
you are propagating it.
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class Main {
|
||||||
|
static void example() throws ArithmeticException;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Rust is a lot closer to this as it enforces that you handle errors. The main
|
||||||
|
difference is that instead of using a special syntax for error handling, it's
|
||||||
|
built into the return type of the function directly. Which is why you'll see
|
||||||
|
functions like this:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn example() -> Result<String, io::Error>;
|
||||||
|
```
|
||||||
|
|
||||||
|
This sometimes makes error handling a little harder, but luckily we have many
|
||||||
|
tools that can help us handle errors.
|
||||||
|
|
||||||
|
## When you don't care about the error
|
||||||
|
|
||||||
|
Sometimes you just don't care about the error. Perhaps the error is impossible
|
||||||
|
to recover from and the best you can do is print an error message and exit, or
|
||||||
|
how you handle it is the same regardless of what the error is.
|
||||||
|
|
||||||
|
### To just exit
|
||||||
|
|
||||||
|
Two great options in this case is [die](https://crates.io/crates/die) and
|
||||||
|
[tracing-unwrap](https://crates.io/crates/tracing-unwrap). Both of these options
|
||||||
|
allow you to unwrap a `Result` type, and print a message if it's an `Error` and
|
||||||
|
exit. `die` allows you to pick the error code to exit with, while
|
||||||
|
`tracing-unwrap` uses the [tracing](https://crates.io/crates/tracing) logging
|
||||||
|
framework. You can also always use the built-in [unwrap or expect](https://learning-rust.github.io/docs/e4.unwrap_and_expect.html) functions.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// die
|
||||||
|
let output = example().die_code("some error happened", 12);
|
||||||
|
// tracing-unwrap
|
||||||
|
let output = example().unwrap_or_log()
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are writing a function that might return any type of error, then
|
||||||
|
[anyhow](https://crates.io/crates/anyhow) is your best option.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn main() -> anyhow::Result<()> {
|
||||||
|
let output = example()?;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## When you do care about the error
|
||||||
|
|
||||||
|
If you do care about what type of error you return, then you need
|
||||||
|
[thiserror](https://crates.io/crates/thiserror). `thiserror` allows you to write
|
||||||
|
your own error types and propagate errors.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum ExampleError {
|
||||||
|
#[error("The error message for this type")]
|
||||||
|
Simple(String),
|
||||||
|
#[error("An error that you are propagating")]
|
||||||
|
FileError(#[from] io::Error),
|
||||||
|
}
|
||||||
|
```
|
Loading…
Reference in a new issue