# Notes These are things from the book I want to have in a document to quickly find again. This means I don’t write down things I have or would want to look up in the documentation or book again anyways. ## Chapter 1 - Rust macros are called with a `!` at the end of its name. - `cargo check` can be used to check if the code compiles, but is much faster than actually producing a binary. ## Chapter 2 - Rust has a [prelude](https://doc.rust-lang.org/std/prelude/index.html)—a list of things that is imported into every single rust program. - Cargo’s `dependencies` section uses [Semantic Versioning](https://semver.org/). - Cargo can build and serve documentation for a project’s depencencies locally by running `cargo doc --open`. - Rust allows shadowing, which means re-using a variable name e.g for type conversions. - Variable types are annotated with a colon, e.g. `let number: u32 = …`. - The underscore is used as a catchall value, e.g. in `Err(_)` to catch any errors when using `match`. ## Chapter 3 ### Variables - You can use the prefix `r#` in variable or function names when things from C libraries for example are named as a keyword from Rust. - `const` types must *always* be annotated. - Rust doesn't catch “index out of bounds” errors from arrays during compile time. Instead, it will “panic” during runtime, *before* any memory has been accessed. ### Functions - Rust’s convention for function names is snake\_case. - Rust separates “statements“, which do not return a value, and “expressions“, which do. - Assignments are not expressions. - Expressions don’t have a semicolon at the end. - The last expression of a function in Rust is implicitly the return value, although you can use `return` to do so. - When the compiler says `()`, it means “no value” (it’s an empty tuple). ### Control Flow - Conditions, i.e. for `if` expressions, *must* return a `bool`. There’s no implicit conversion e.g. from integers or so. - Because `if` is an expression, it can be used in `let` statements. - Collections can be iterated using `for element in array.iter() {…`. It’s safer and faster than for example doing so with `while`. - A loop to be run a certain amount of times could be a `for` loop with a `Range`: `for number in (1..25).rev() {…`. ## Capter 4 ### Ownership - Where a scope ends, the `drop` function for all the variables used in it is called so the memory gets deallocated. - Binding the same value in different variables is different between simple and complex types. Simple types get copied, while for complex types, the *pointer* to the content is copied. - If a complex type is copied, the original one is no longer valid to avoid double free errors. This is effectively a *move* of the variable. - Rust never automatically creates “deep” copies of data, which is inexpensive in terms of runtime performance. - “Deep” copies can be created using `clone`. - Internally, this concept is implemented using the conflicting traits `Copy` and `Drop`. - Passing a variable to a function will also move or copy it. - References circumvent the problem of havin to pass variables back in order to use them again, because they would get out of scope otherwise. They allow to use a value without taking ownership of it. This is called borrowing, because e.g. a function can use the value, but not drop it. - In order to mutate it, references have to be declared mutable as well. - Only one mutable reference to a variable is allowed per scope to prevent data races. - A `slice` is a data type that does not have ownership. - A `string slice` is a reference to part of a `String`. - String literals are slices. - Slices work for all collections. # Chapter 5 - Rust doesn’t allow to mark only certain fields of a struct as mutable. The whole struct has to be. - Rust has automatic referencing and dereferencing, so there’s no need for a `->` operator on structs. # Chapter 6 - Rust does not have a `null`, and the `Option` enum is a way to compensate that. This enum is included in the prelude. - Match compares the return value of the given expression to arbitrary patterns in the arms, and executes the code associated with the first one it matches. This code then itself needs to return something for the entire match expression. - Single `enum` variants can hold additional values. - `_` is a “catchall” in `match` expressions. Since `match` is exhaustive, it helps covering any possible match without listing them one by one. - `if let` is a shortcut for matches where only one arm is interesting to us. # Chapter 7 - Everything is `private` by default. - Structs with private members require public functions to create an instance of them. # Chapter 8 ## Vectors - A `String` is a collection of characters. - `&v[100]` returns a reference to a vector’s element at 100 and crashes if that index doesn’t exist, while `v.get(100)` returns an `Option` which can be matched. ## Strings - `String` is not part of the core language, but rather of Rust’s standard library. - `String` is a wrapper over `Vec`. - The data in Strings is hold as bytes, which does not always corelate to characters. ## Hash Maps - `get` returns an option. - `insert` by default replaces values of keys that already exist. # Chapter 9 - Rust separates errors in recoverable ones (`Result`) and unrecoverable ones (`panic!`). - `Result` and its variants are part of the prelude. - For functions that return a `Result`, the `?` operator can be used as as shorthand for returning either `Ok` or panicing with `Err`. # Chapter 10 ## Generics - Generics are a tool for reducing code duplication. - Generics don’t lead to slower code compared to concrete types (the duplication is done by the compiler, if you will). ## Traits - Where Rust has traits, other languages might have interfaces. It’s a concept to tell the compiler about the functionality of certain types in an abstract way. - You can have default implementations. - There is lots of syntax sugar involved as far as traits are concerned. ## Lifetimes - Lifetimes exist in Rust to avoid dangling references and make sure references will become invalid at a certain point. - There is a set of *lifetime elision rules* which automatically apply reoccuring lifetime patterns if none are explicitly specified. - TODO: I didn’t completely understand this from the book and the examples. I should find another source to get this explained in a way I understand better. # Chapter 11 - Tests fail when something in a test function panics. - The `assert!` macro evaluates a boolean value and panics if it’s `false`. - All the `assert!` macros also take optional parameters to print custom error messages. - Adding `#[should_panic]` after ´#[test]` can be used to check if the error handling works correct. # Chapter 12 - Per convention, programs should be split into a `main.rs` and a `lib.rs`, where the latter contains all the logic, and the main handles running the program.