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