learning-rust/src/errors.rs

143 lines
3.4 KiB
Rust

//! ## Panic
//!
//! [`panic`](https://doc.rust-lang.org/std/macro.panic.html) is a
//! good way to crash a program:
//!
//! - `panic!();`
//! - `panic!("Error message");`
//! - `panic!("this is a {} {message}", "fancy", message = "message");`
//!
//!
//! ## TODO
//!
//! `todo!()` is nice for not yet implemented methods:
//!
//! ```
//! fn test() -> String {
//! todo!()
//! }
//! ```
//!
//! It's nice because it uses the type system to make it just compile
//! with some kind of `never` type, it is the type `!`, and we can use
//! the never type in our functions, like `-> !`.
//!
//!
//! ## Unwind
//!
//! The `unwind` step is the operation that happen during a rust
//! exit. It is related to `RUST_BACKTRACE=1`.
//!
//! It liberates allocated resources by calling drop from the
//! [Drop](https://doc.rust-lang.org/std/ops/trait.Drop.html) trait.
//!
//! `drop` is also called when a resource gets out of a scope.
//!
//! It can be skipped by using:
//!
//! ```toml
//! [profile.release]
//! panic = 'abort'
//! ```
//!
//! ## Option
//!
//! It's a good way to express (recoverable) errors.
//!
//! By returning `Some(thing)` on success or `None` on failure.
//!
//! On `Option` there s an `and_then` that's executed (with the
//! unwinded value) only if the option is not `None`.
//!
//! - `and_then`: the given lambda should return a new `Option`.
//! - `map`: the given lambda should return a value, `map` changes the `Option` value in-place.
//! - `unwrap_or_else`: the given lambda should return a default value in case the `Option` is `None`.
//!
//!
//! ## Result
//!
//! ```
//! enum Result<T, E> {
//! Ok(T),
//! Err(E),
//! }
//! ```
//!
//! It's like `Option` but the failing case can contain a string.
//!
//!
//! ## The `?` operator
//!
//! It's a "replacement" for `.unwrap()`.
//!
//! `something()?` is a kind of unwrap, but in case of error it
//! `returns` the same `Err`. It "propagates" it. So it only work in a
//! function that returns a `Result` with the same or compatible error
//! type.
//!
//! `main` is allowed to return a result, like:
//!
//! ```
//! fn main() -> Result<(), Box<dyn Error>> {
//! }
//! ```
//!
//! `Box dyn` means "I don't know the size, it's in the heap". It's a
//! way to tell "any object implementing the `Error` trait".
//!
//!
//! ## Error types
//!
//! ### String
//!
//! It's a bit limited, but it works.
//!
//!
//! ### `std:error::Error`
//!
//! It's a trait, it has a `cause` and a `source`, it reminds an exception.
//!
//!
//! ### Using an Enum
//!
//! It allows to list all errors.
//!
//! It works well with the
//! [thiserror](https://docs.rs/thiserror/1.0.50/thiserror/) create.
//!
//! It has many advantages: It can be used in pattern matching, can
//! has strings liked to errors for humans, can convert from known
//! errors using `#[from]`, each case can store specialized values.
//!
//!
//! ### Anyhow
//!
//! Provides an `anyhow::Result`, and can unify any error types.
//!
//! See [on docs.rs](https://docs.rs/anyhow/latest/anyhow/).
//!
//!
//!
//!
fn _i_do_not_return() -> ! {
loop {}
}
fn test_unwrap_or_else() {
let mut dict = std::collections::HashMap::new();
dict.insert("Key".to_owned(), "Value".to_owned());
let default = "Not found".to_owned();
let result = dict.get("Key").unwrap_or_else(|| &default);
assert!(result == "Value");
let result = dict.get("nonono").unwrap_or_else(|| &default);
assert!(result == "Not found");
}
pub fn main() {
test_unwrap_or_else();
}