143 lines
3.4 KiB
Rust
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();
|
|
}
|