2020-06-15
# [The Rust Programming Language](https://doc.rust-lang.org/book/)
[正體中文版](https://rust-lang.tw/book-tw/)
- Rust 1.41.0 + `edition="2018"` (*Cargo.toml* ?)
* install/update → [Ch1](#11-Installation)
* editions → Appendix E
- 2018 Edition improvements included
- Rust’s backward compatibility
---
# Foreword
# Introduction
---
# 1. [Getting Started](https://doc.rust-lang.org/book/ch01-00-getting-started.html)
gogo~
## 1.1. [Installation](https://doc.rust-lang.org/book/ch01-01-installation.html)
- install Rust tools by `rustup`
- stability guarantees?
- **Linux**
* copy and run the `curl` command
* requires a C compiler/linker (??
- **Windows**
* download and run *[rustup-init.exe](https://www.rust-lang.org/tools/install)*
* requires *[C++ build tools for Visual Studio](https://www.visualstudio.com/downloads/)*
- after installed
* update: `rustup update`
* uninstall: `rustup self uninstall`
* troubleshoot: `rustc --version`
* local doc: `rustup doc`
## 1.2. [Hello, World!](https://doc.rust-lang.org/book/ch01-02-hello-world.html)
- as usual
* by command line
* or your favorite IDE 💬 [Rust -- Tools](https://www.rust-lang.org/tools)
- create directories (not required but ease)
- run `main.rs`
* naming convention: `hello_world.rs` (underscore to separate)
* `rustc main.rs`
* then, `./main` or `.\main.exe`
- anatomy
* entry point: `fn main()` (no parameter, return nothing)
* coding style (there will be `rustfmt`)
```rust
fn main() {
}
```
* `println`
* indent: 4 spaces (not tab)
* macro/function (with/without `!`)
* string: `"abc"`
* end the line with `;`
- compile
* results to executable
* can run without Rust installed
* bigger projects require build tool -- *Cargo*
## 1.3. [Hello, Cargo!](https://doc.rust-lang.org/book/ch01-03-hello-cargo.html)
- Cargo: build system + package (dependencies) manager
* 💬 [Rustaceans](https://www.rustaceans.org/): Rust fans
* check: `cargo --version`
- create: `cargo new hello_cargo`
* new Git repository and *.gitignore*
+ `--vcs` flag for different/no version control system
+ 💬 otherwise, [`cargo init`](https://doc.rust-lang.org/cargo/commands/cargo-init.html) in existing directory (simply `cargo new` does not work)
* *Cargo.toml* in [TOML](https://github.com/toml-lang/toml) format
+ `[package]`: name, version, author (fix if not correct), edition (Appendix E)
+ `[dependencies]`
* *src/main.rs*
+ place source files under *src/* directory, top-level is for README, license, config, etc.
+ everything should be in its place
- build: `cargo build`
* */target/debug/hello_cargo* or *\target\debug\hello_cargo.exe*
* *Cargo.lock* tracks versions of dependencies (auto generated, do not edit!)
* `cargo run`: build (if required) and run
* `cargo check`: compile without making executable (good for developing)
- release: `cargo build --release`
* */target/release*
* optimize (run faster but build slower)
- easier to maintain larger projects
* the convention
# 2. [Programming a Guessing Game](https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html)
- learning by doing: guessing game
- 💬 [step by step commits](https://github.com/yipo/rust-book-project-chapter/tree/ch02-guessing-game)
[iter #0](https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html#setting-up-a-new-project)
- **new project**
1. `cargo new guessing_game`
2. check *Cargo.toml*
3. check *src/main.rs*
4. `cargo run` (rapidly iterate)
- 💬 version control `Cargo.lock`? [Cargo.toml vs Cargo.lock](https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html)
* binary → yes; library → no
[iter #1](https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html#processing-a-guess)
- **prompt**
* bring `io` library into scope: `use std::io`
+ `std::prelude`
* `fn`
* `println!`
- **variable**
* create a variable: `let`/`let mut` (immutable by default)
* comment: `//`
* return a new `String` instance: `String::new()`
+ `String` is growable, UTF-8 encoded
+ `::` (associated) and static method
+ `new` convention
- **read line**
* `std::io::stdin` if lack of `use std::io`
* [`std::io::Stdin`](https://doc.rust-lang.org/std/io/struct.Stdin.html)
* `&` (reference) and `mut` (mutable)
- **handle error**
* break long lines
* `Result`s
+ `read_line()` returns `io::Result`
+ generic [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
* enum
+ be one of **a fixed set of values** (*variants*) → Ch6
+ `Ok` (success and the output) or `Err` (fail and the reason)
* `.expect()`
+ `Ok`: return the output (here, the number of bytes entered)
+ `Err`: crash and display the message
+ must be used
+ more error handling → Ch9
- **print value** by `{}`
- **test** using `cargo run`
[iter #2](https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html#generating-a-secret-number)
- **using crate**
* Rust team provide `rand` crate (not in `std`)
* binary/library crate
* add the line under `[dependencies]` section
+ [semantic version](https://semver.org/) (*SemVer*)
+ `0.5.5` = `^0.5.5`
* `cargo build`
+ registry: [crates.io](https://crates.io/)
+ `libc`, `rand_core` are `rand`'s dependencies
+ rebuild only the changed part
- **reproducible build** with *Cargo.lock*
* not upgrade unless explicitly do
* `cargo update`: looks for `0.6.0` > ver > `0.5.5`
* `rand = "0.6.0"` to use `0.6.x`
* more → Ch14
- **generate random number**
* `use rand::Rng` and `Rng` trait → Ch10
* `rand::thread_rng()`
+ `.gen_range(1, 101)`
* (`cargo doc --open`: build doc of dependencies)
* print the number and test
[iter #3](https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html#comparing-the-guess-to-the-secret-number)
- **compare**
* `use` `std::cmp::Ordering` enum: `Less`/`Greater`/`Equal`
* call `.cmp()` on everything can be compared
* `match` expression → Ch6/18
+ *arm* and *pattern*
+ checked in turn
* mismatched types (strong/static type system)
+ type inference: string and number (`i32` by default)
- **fix**
* *shadow* → Ch3
* `.trim()` to deal with `5\n`
* `.parse()`
+ `let guess: u32` 💬 how `.parse()` know the type? infer `secret_number`'s type?
+ `.expect()` again
[iter #4](https://doc.rust-lang.org/book/ch02-00-guessing-game-tutorial.html#allowing-multiple-guesses-with-looping)
- infinite **loop** by `loop {}`
* be sure to indent
- **quit** by `break`
* ctrl-c or typing `quit` is not good
- **handle invalid input**
* take `match` instead of `expect` that crashes
* `Err(_)`: `_` to catch all
* retry by `continue`
- remove `println!` that prints the secret number
# 3. [Common Programming Concepts](https://doc.rust-lang.org/book/ch03-00-common-programming-concepts.html)
- the part of Rust that the same as other languages
- keywords → Appendix A
## 3.1. [Variables and Mutability](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html)
- *immutable* by default: push you to write concurrency in good way
- error: `cannot assign twice to immutable variable`
* frustrating... not mean you're not a good programmer 😌
* avoid bugs
* easier to trace code
- add `mut` to be mutable
* trade-off: mutate the member **vs** get a new copy
### [Constants?](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants)
- `const` ≠ `let`
* cannot `mut`: always immutable
* type *must* be annotated
* in any scope (e.g. global)
* const expr only (cannot be any value at runtime) 💬 like `#define`/`constexpr` in C/C++
- example
```rust
const MAX_POINTS: u32 = 100_000;
```
* naming convention for constants
* underscores in numeric for readability
### [Shadowing](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing)
- it's ok to declare a new variable with the same name
* no error/warning
* not to assign; without `mut`
* for some kinds of transformation
* the type can be changed (but `mut` not)
## 3.2. [Data Types](https://doc.rust-lang.org/book/ch03-02-data-types.html)
- scalar/compound
- static type: decided at compile time
* usually infer, sometimes must annotate 💬 C++: built-in `auto`
### [Scalar Types](https://doc.rust-lang.org/book/ch03-02-data-types.html#scalar-types)
single value
- **integer**
* `i8`/`i16`/`i32`/`i64`/`i128` for signed
* `u8`/`u16`/`u32`/`u64`/`u128` for unsigned
* `isize`/`usize` are architecture depended
* literal
+ type suffix: `42u8`
+ separator: `_`
+ `0xff`, `0o77`, `0b1111`, `b'A'` (`u8` only)
* overflow
+ panic in debug mode
+ [`Wrapping`](https://doc.rust-lang.org/std/num/struct.Wrapping.html)
- **floating point**
* `f32`/`f64`
- operation: `+`, `-`, `*`, `/`, `%`
- **boolean**
* `bool` (`true`/`false`)
- **character**
* single quote
* 4 bytes; support Unicode → Ch8
### [Compound Types](https://doc.rust-lang.org/book/ch03-02-data-types.html#compound-types)
group multiple values
- **tuple**
* fixed length; variety types
```rust
let t: (i32, f64, u8) = (50, 6.4, 1);
```
* *destructuring*
```rust
let (x, y, z) = t;
```
```rust
let x = t.0;
let y = t.1;
let z = t.2;
```
- **array**
* fixed length; same type
```rust
let a = [1, 2, 3, 4, 5];
```
* scenario
+ on stack (rather than heap)
+ ensure length -- e.g. 12 months (otherwise, `vector` → Ch8)
* array's type
```rust
let a: [i32; 5] = [1, 2, 3, 4, 5]
```
* initialize
```rust
let a = [3; 5] // [3, 3, 3, 3, 3]
```
* access
```rust
let x = a[0];
let y = a[1];
```
+ boundary check at runtime
## 3.3. [Functions](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html)
- **function**
* entry point: `fn main()` (`fn` to declare function)
* naming convention: `snake_case` (all lowercase, underscore separate)
* don't care the order function defined
- **parameter**
* *argument*s are values for *parameter*s (variables)
* function signature
* must declare the type: `fn func(x: i32)`
* multiple arguments: `fn func(x: i32, y: i64)` (can be different type)
- **function body**: **statement** × n (+ ending **expression**)
* **statement** do not return value, cannot assign to a variable
+ `let` statement (different from C, Ruby; `x = y = 6` does not work)
+ function definition
* **expression** results to a value
+ `5 + 6`
+ function call, macro call
+ `{}` with ending expression (without `;` at the end)
- **return value**
```rust
fn func() -> i32 {
5
}
```
* type: declare by `->`
* value
+ ending expression (of function body)
+ or `return` early
* `mismatched types`
+ `help: consider removing this semicolon` 💬 so nice
+ empty tuple `()` by default
## 3.4. [Comments](https://doc.rust-lang.org/book/ch03-04-comments.html)
- `//`: comment until the end of line
- more → Ch14
## 3.5. [Control Flow](https://doc.rust-lang.org/book/ch03-05-control-flow.html)
- branch (`if`/`else`) and loop (`loop`, `while`, `for`)
- **if**
```rust
if n < 5 {
// true
} else {
// false
}
```
* optional `else` block
* condition must be `bool` (no implicit cast)
- **else if**
* check in turn
* consider to use `match` → Ch6
- **if** in **let** 💬 as *ternary operator* (`?:`) do
```rust
let x = if condition { 5 } else { 6 };
```
* `if` is expression
* types must be matched
- **loop**
```rust
let x = loop {
if condition {
break result;
}
};
```
* forever, until `break` (or ctrl-c)
* could `break` with value
- **while**
* clearer than `loop`+`if`+`else`+`break`
- **for** each element in one collection
```rust
for num in [10, 20, 30, 40, 50].iter() {
println!("{}", num);
}
```
* better then using `while`
* safe: avoid incorrect index limit
* fast: not to check the condition at runtime
* concise
* `Range` to count down
```rust
for num in (1..4).rev() {
println!("{}", num);
}
```
### [Summary](https://doc.rust-lang.org/book/ch03-05-control-flow.html#summary)
- how about some homework
- ready to move on: ownership
# 4. [Understanding Ownership](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html)
the way Rust manage memory (with safety guarantee)
## 4.1. [What is Ownership?](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html)
- ways to manage memory
* garbage collect
* explicitly allocate/free
* **Rust:** rules checked at compile time (no overhead at runtime)
- encourage: keep at it!
:::info
### [The Stack and the Heap](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#the-stack-and-the-heap)
- Rust do care about stack/heap
- both are parts of memory
* **stack**
+ like a pile of plates
+ first in (push), last out (pop)
+ must have a known, fixed size
+ access the known address
* **heap**
+ like seats in a restaurant
+ allocate empty space that big enough
+ require to search and book-keep
+ follow the pointer (slower)
- closer data means faster
- function call stack
- ownership handles these
:::
### [Ownership Rules](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#ownership-rules)
1. each value has one variable as *owner*
2. only *one* owner at a time
3. when owner *out of scope*, value dropped
### [Variable Scope](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#variable-scope)
- the range that an item is valid
(like other languages so far)
### [The `String` Type](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#the-string-type)
- require a data type stored on the heap (rather than stack) to illustrate
* `String` as example, also apply on any others
- difference
* **string literal:** immutable, must be known while developing
* **`String`:** can store unknown amount of text
- `::from()` to create `String` from string literal
* can be mutable
* method syntax → Ch5
* namespace of module → Ch7
### [Memory and Allocation](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#memory-and-allocation)
- difference (again)
* **string literal:** immutable, hard-coded, fast
* **`String`:** mutable, need allocation...
- allocation
* **request:** `::from()` by us
* **return:** (different ways...) `::drop()` when out of scope by Rust
- simple right now; may unexpected with multiple variables
#### [Ways Variables and Data Interact: Move](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#ways-variables-and-data-interact-move)
- let's assign values
- **integer:** fixed size, on the stack
* simply make a copy
- **`String`:** ptr to data (on the heap), len, (capacity)
* simply make a copy (*shallow copy*) → *double free* error
* copy the data as well (*deep copy*) → very expensive
* Rust: *move* → let `s1` become invalid
- Rust never auto deep copy
#### [Ways Variables and Data Interact: Clone](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#ways-variables-and-data-interact-clone)
- to *deep copy* → `.clone()`
* indicator for something expensive
#### [Stack-Only Data: Copy](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#stack-only-data-copy)
- no `.clone()` but still copied?
* because no different between deep/shallow copy (on the stack)
- `Copy` trait
* older variable still usable after assignment
* otherwise, `Drop` trait
- general rule of `Copy`
* Boolean, integer, floating point, char
* tuple only contains `Copy`
### [Ownership and Functions](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#ownership-and-functions)
pass value to function = assign value
### [Return Values and Scope](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#return-values-and-scope)
pass value to function, but not to give ownership? → *reference*
## 4.2. [References and Borrowing](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html)
- not to take/return ownership → borrow by *reference*
* caller: `&s` -- create a reference to `s`
* callee: `&String` -- accept a reference
- do not have ownership
* do not have to return/drop
### [Mutable References](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#mutable-references)
- (immutable) reference cannot be modified → *mutable* reference
* caller: `&mut s` -- create a mutable reference
* callee: `&mut String` -- accept a mutable reference
- to prevent *data race*
* only one mutable reference in a scope
+ create new scopes by `{}`
* either one mutable reference, or any immutable references
### [Dangling References](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#dangling-references)
- checked at compile-time
- no dangling guaranteed at run-time
### [The Rules of References](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references)
1. either...
* one mutable reference, or
* any number of immutable references
2. reference must always be valid
## 4.3. [The Slice Type](https://doc.rust-lang.org/book/ch04-03-slices.html)
- *slice* type
* reference a contiguous sequence
* (also) do not have ownership
- problem: find the first word
- first try: return the index
* pass without ownership -- `&String`
* element by element -- `.as_bytes()`
* iterator over it -- `.iter()`
+ with the index in tuple -- `.enumerate()`
* destructure the tuple -- `(i, &item)`
- cons: no guarantee to a valid string
+ even more for `second_word()`
### [String Slices](https://doc.rust-lang.org/book/ch04-03-slices.html#string-slices)
- `&s[0..5]` -- *string slice* is
* `&s` -- a reference
* `[0..5]` -- to part of a string
- `[begin..end]`
* the `end` one is not included (length = end - begin)
- shortcut
* `&s[..2]` = `&s[0..2]`
* `&s[3..]` = `&s[3..len]`
* `&s[..] ` = `&s[0..len]`
- rewrite `first_word()`
* the *string slice* type -- `&str`
- compile error reported if index used after string cleared
* because of *borrowing*: ether one mutable, or any immutable references
#### [String Literals Are Slices](https://doc.rust-lang.org/book/ch04-03-slices.html#string-literals-are-slices)
a *string literal* (`&str`) is an *immutable reference*
#### [String Slices as Parameters](https://doc.rust-lang.org/book/ch04-03-slices.html#string-literals-are-slices)
`&str` parameter to receive both `&String` and `&str`
### [Other Slices](https://doc.rust-lang.org/book/ch04-03-slices.html#other-slices)
also works on array slice (like `&[i32]`) → Ch8
### [Summary](https://doc.rust-lang.org/book/ch04-03-slices.html#summary)
- ensure memory safety at compile time: ownership, borrowing, slice
- affect lots of other parts of Rust
# 5. [Using Structs to Structure Related Data](https://doc.rust-lang.org/book/ch05-00-structs.html)
- **`struct` (*structure*):** custom type to name and group related values
* `struct` vs tuple
* method and associated function
* `struct` and `enum` → Ch6
## 5.1. [Defining and Instantiating Structs](https://doc.rust-lang.org/book/ch05-01-defining-structs.html)
- feature
* pieces can be different types (same as tuple)
* name each piece of data
+ clear meaning
+ access by name (rather than order)
- usage
* define a struct
* create an instance
+ don't have to be same order
* get a specific value
- mutable struct: cannot be partial mutable
- convenient shorthands...
### [Field Init Shorthand](https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-the-field-init-shorthand-when-variables-and-fields-have-the-same-name)
- simply `name` if variable/field have the same name
* instead of `name: name`
### [Struct Update Syntax](https://doc.rust-lang.org/book/ch05-01-defining-structs.html#creating-instances-from-other-instances-with-struct-update-syntax)
- `..user1` -- all the rest fields have the same value as `user1`'s
### [Tuple Structs](https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types)
- have a name for entire struct
- **but** no name for each field
- become a new type
* even corresponding fields are the same type
- access the value: `.` + index
### [Unit-Like Structs Without Any Fields](https://doc.rust-lang.org/book/ch05-01-defining-structs.html#unit-like-structs-without-any-fields)
- the unit type: `()`
- a trait without any data → Ch10
:::info
### [Ownership of Struct Data](https://doc.rust-lang.org/book/ch05-01-defining-structs.html#ownership-of-struct-data)
- `String` rather than `&str` in the struct
* own the data as long as the struct is valid
- store references in a struct? *lifetime* → Ch10
* `^ expected lifetime parameter`
:::
## 5.2. [An Example Program Using Structs](https://doc.rust-lang.org/book/ch05-02-example-structs.html)
- when to use structs? example: calculate the rectangle area
* refactor until using structs instead
- **first try:** variables `width1` and `height1`
* cons: one rectangle but two parameters
### [Refactoring with Tuples](https://doc.rust-lang.org/book/ch05-02-example-structs.html#refactoring-with-tuples)
- **better one:** one tuple `rect1`
* pros: a bit of structure
* cons: `.0` and `.1` are confusing
### [Refactoring with Structs: Adding More Meaning](https://doc.rust-lang.org/book/ch05-02-example-structs.html#refactoring-with-structs-adding-more-meaning)
- **much better:** one struct with `width` and `height` fields
### [Adding Useful Functionality with Derived Traits](https://doc.rust-lang.org/book/ch05-02-example-structs.html#adding-useful-functionality-with-derived-traits)
- to see the values while debugging... `println!("{}", rect1);`
1. doesn't implement `std::fmt::Display`
* may be able to use `{:?}` instead
2. doesn't implement `std::fmt::Debug`
* add `#[derive(Debug)]` or implement `std::fmt::Debug`
3. add `#[derive(Debug)]` to explicitly opt in
* `{:#?}` for pretty-print
- many other traits for `derive` → Appendix C
## 5.3. [Method Syntax](https://doc.rust-lang.org/book/ch05-03-method-syntax.html)
- *method*s are like functions
* declared with `fn` keyword
* have parameters and a return value
* contain some code to be called
- **but** within the context of a struct (enum or trait object)
* first parameter is `self` (instance of struct)
### [Defining Methods](https://doc.rust-lang.org/book/ch05-03-method-syntax.html#defining-methods)
- change `area` function to a method
1. move `area` function into `impl` (implementation) block of `Rectangle`
2. change first parameter to `&self`
* use `self.` to access variables in the body
3. call `area` method by *method syntax* -- `.method_name(argument, …)`
- `&self` instead of `rectangle: &Rectangle`?
* Rust knows the type of `self` due to `impl Rectangle`
- `&` before `self`?
| first param | meaning | note |
|:-----------:|:---------------- | ---- |
| `self` | take ownership | rare
| `&self` | borrow immutably | read only
| `&mut self` | borrow mutably | write
- benefit
* *method syntax*
* not to repeat the type of `self`
* **for organization:** all the things we can do with the type are here
+ users don't search them in various places
:::info
### [Where’s the `->` Operator?](https://doc.rust-lang.org/book/ch05-03-method-syntax.html#wheres-the---operator)
- C++
* ` .method()` for an object
* `->method()` for a pointer to an object
+ i.e., `(*ptr).method()`
- Rust: *automatic referencing and dereferencing*
* auto add `&`, `&mut`, or `*` to match the signature
* no `->`
* because methods have a clear receiver (💬 can Rust have overloading functions?
:::
### [Methods with More Parameters](https://doc.rust-lang.org/book/ch05-03-method-syntax.html#methods-with-more-parameters)
practice: whether one rectangle can hold another?
1. name the method `can_hold` within the `impl Rectangle` block
2. take an immutable borrow of another `Rectangle` as a parameter
3. call the method by passing `&rect2`
4. return a `bool` value (by checking width and height)
### [Associated Functions](https://doc.rust-lang.org/book/ch05-03-method-syntax.html#associated-functions)
- *associated function*
* no `self` parameter (so not a method)
* like `String::from`
- often used for constructors
* example: `Rectangle::square`
* call by `::` syntax
### [Multiple `impl` Blocks](https://doc.rust-lang.org/book/ch05-03-method-syntax.html#multiple-impl-blocks)
allowed to have multiple `impl` blocks → useful in Ch10
### [Summary](https://doc.rust-lang.org/book/ch05-03-method-syntax.html#summary)
- to create custom types: structs (and enum → Ch6)
* name for clear meanings
* methods and associated functions
# 6. [Enums and Pattern Matching](https://doc.rust-lang.org/book/ch06-00-enums.html)
- **`enum` (*enumeration*):** a type defined with its possible variants
* (in Rust) similar to *algebraic data type*s of functional programming
- `Option` can be either something or nothing
- `match` values by patterns
- `if let`: another idiom to handle enums
## 6.1. [Defining an Enum](https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html)
- situation: IP v4/v6
```rust
enum IpAddrKind {
V4,
V6,
}
```
* be one of them (not both at the same time)
### [Enum Values](https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html#enum-values)
- create instances of `IpAddrKind` type: `IpAddrKind::V4`, `IpAddrKind::V6`
* same on function parameters and arguments
- concise than an enum in a struct -- attach data to enum variants
```rust
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
```
* can have different types and amounts of associated data
* standard library already do this → <code><a href="https://doc.rust-lang.org/std/net/enum.IpAddr.html">std::net::IpAddr</a></code>
+ can still have our own `IpAddr` due to namespace → Ch7
- another example: a wide variety of types
* similar to different kinds of `struct` definitions
* **but** under the `Message` type -- by which it's easily to accept any kinds of these
* methods on enums
### [The Option Enum and Its Advantages Over Null Values](https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html#the-option-enum-and-its-advantages-over-null-values)
- to encode a value that could be something or nothing
- the problem of *null*: use a null value as a not-null one
* extremely common bugs (in other languages)
- Rust does not have *null*s -- `Option<T>`
```rust
enum Option<T> {
Some(T),
None,
}
```
* so useful that...
+ in the prelude of [the standard library](https://doc.rust-lang.org/std/option/enum.Option.html)
+ use `Some` and `None` without `Option::` prefix
* `<T>`: generic type parameter → Ch10
* example
```rust
let some_number = Some(5);
let some_string = Some("hello");
let absent_number: Option<i32> = None;
```
+ `Some`: the type can be inferred
+ `None`: must be told
- why?
* `Option<T>` can't be used as `T` due to different types (can be checked by compiler)
* must convert `Option<T>` to `T` (before doing any `T` operations)
* must explicitly handle the case of null
- how?
* [a large number of methods](https://doc.rust-lang.org/std/option/enum.Option.html) for variety situations
* `match`: run different code by variants
## 6.2. [The `match` Control Flow Operator](https://doc.rust-lang.org/book/ch06-02-match.html)
- `match`: execute code based on which pattern matches
* all kinds of patterns → Ch18
* pros
+ expressiveness
+ compiler confirms if all cases are handled
* like a coin-sorter
- example
```rust
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
```
* `match` + *expression* (can be any type)
* each arm: *pattern* `=>` *some code*
+ compared in order
+ becomes the value `match` returns
+ `{ }` for multi-line code
### [Patterns that Bind to Values](https://doc.rust-lang.org/book/ch06-02-match.html#patterns-that-bind-to-values)
- extract values out from enum variants
- example: to collect different designs (for each state) of quarters
```rust
match coin {
…
Coin::Quarter(state) => {
println!("state: {:?}", state);
25
}
}
```
### [Matching with `Option<T>`](https://doc.rust-lang.org/book/ch06-02-match.html#matching-with-optiont)
handle `Option<T>` by `match` just as other enums
### [Matches Are Exhaustive](https://doc.rust-lang.org/book/ch06-02-match.html#matches-are-exhaustive)
any case not handled? compiler reports errors
### [The `_` Placeholder](https://doc.rust-lang.org/book/ch06-02-match.html#the-_-placeholder)
- match all the rest
* a unit value `()` to do nothing
## 6.3. [Concise Control Flow with `if let`](https://doc.rust-lang.org/book/ch06-03-if-let.html)
- match one pattern and ignore all the rest (shortcut for `match`)
* lose exhaustive check (trade-off)
- `if let` *pattern* `=` *expression* `{ }`
* `else` as `_` placeholder in `match`
### [Summary](https://doc.rust-lang.org/book/ch06-03-if-let.html#summary)
- covered
* `enum`
* `Option<T>` to prevent errors
* `match`/`if let` to extract values from enum
- compiler ensures type safety
# 7. [Managing Growing Projects](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html)
- organize is important (as a project grows)
- techniques to group and encapsulate
## 7.1. [Packages and Crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html)
- **crate**
* a binary or library
* *crate root*: a source file that...
+ Rust compiler starts from
+ and makes up the root module of the crate
+ (for modules → Sec7.2)
- **package**
* one or more crates (provide a set of feature)
+ at least 1 crate (library or binary)
+ at most 1 library crate
* contains *Cargo.toml*
- create a package
* `cargo new` → a package created with *Cargo.toml*
* convention without specify the crate root (same name as the package)
* **binary crate**
+ crate root: *src/main.rs*
+ other binary crates: place files in *src/bin*
* **library crate**
+ crate root: *src/lib.rs*
- for ease to share between projects
- the scope of a crate
## 7.2. [Defining Modules to Control Scope and Privacy](https://doc.rust-lang.org/book/ch07-02-defining-modules-to-control-scope-and-privacy.html)
- module system: module, path, `use`, `pub`, `as`, external package, glob operator
- **module**
* organize code into groups
* control privacy (public/private)
- example: restaurant
* `cargo new --lib restaurant`
* in *src/lib.rs*
```rust
mod front_of_house {
mod hosting {
…
}
mod serving {
…
}
}
```
+ can have nested modules
+ and other definitions: struct, enum, constant, trait, or function
- **module tree**
* *crate root* -- the contents of *src/main.rs* and *src/lib.rs*
+ form the root module named `crate`
* just like a filesystem
## 7.3. [Paths for Referring to an Item in the Module Tree](https://doc.rust-lang.org/book/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html)
- path
* **absolute path** (from a crate root)
+ `crate` or a crate name
* **relative path** (from the current module)
+ `self`, `super` or an identifier in the current module
* separated by `::`
- example
```rust
mod outer {
mod inner {
fn callee() { }
}
}
pub fn caller() {
crate::outer::inner::callee(); // absolute
outer::inner::callee(); // relative
}
```
- choice?
* absolute: move separately
* relative: move together
- module also used for *privacy boundary*
* all items are *private* by default
* child can still access their ancestors
* `pub` to make it *public*
### [Exposing Paths with the `pub` Keyword](https://doc.rust-lang.org/book/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#exposing-paths-with-the-pub-keyword)
- the *callee* function should also be `pub`
- *outer* (without `pub`) can be accessed by sibling
### [Starting Relative Paths with `super`](https://doc.rust-lang.org/book/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#starting-relative-paths-with-super)
- `super`: relative path from the parent
* like `..` in filesystem
- why? in case the items are moved together to another module
### [Making Structs and Enums Public](https://doc.rust-lang.org/book/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#making-structs-and-enums-public)
- `pub` struct
* fields still be private (`pub` each one case-by-case)
* require a `pub` function (to initialize private fields)
- `pub` enum
* all its variants are public
## 7.4. [Bringing Paths into Scope with the `use` Keyword](https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#bringing-paths-into-scope-with-the-use-keyword)
- bring paths into a scope by `use`
* as if they're local items (like symbolic links in filesystem)
* privacy is also checked
* can also `use` by relative paths
### [Creating Idiomatic `use` Paths](https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#creating-idiomatic-use-paths)
- why not bring the *callee* directly? → should `use` the parent model instead
* shows the item isn't locally defined
* avoid name conflict (`fmt::Result`/`io::Result`)
### [Providing New Names with the `as` Keyword](https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#providing-new-names-with-the-as-keyword)
```rust
use std::io::Result as IoResult;
```
### [Re-exporting Names with `pub use`](https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#re-exporting-names-with-pub-use)
- the item we bring into by `use` is private
* combine `pub` to make it public (*re-exporting*)
- why? provide different structure from internal one
### [Using External Packages](https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#using-external-packages)
- example: `rand`
1. list them in *Cargo.toml*
```toml
[dependencies]
rand = "0.5.5"
```
* Cargo downloads the package and its dependencies
* then `rand` is available in our project
2. bring items from crates by `use`
```rust
use rand::Rng;
```
- `std` is already shipped with Rust
### [Using Nested Paths to Clean Up Large `use` Lists](https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#using-nested-paths-to-clean-up-large-use-lists)
```rust
use std::io::{self, Write};
```
### [The Glob Operator](https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#the-glob-operator)
```rust
use std::collections::*;
```
- may hard to tell...
* what names are in the scope
* where a name was defined
- often used when testing
## 7.5. [Separating Modules into Different Files](https://doc.rust-lang.org/book/ch07-05-separating-modules-into-different-files.html)
```rust
mod outer {
pub mod inner {
pub fn callee() { }
}
}
pub fn caller() { }
```
the module tree is the same as...
- *src/lib.rs*
```rust
mod outer;
pub fn caller() { }
```
- *src/outer.rs*
```rust
pub mod inner;
```
- *src/outer/inner.rs*
```rust
pub fn callee() { }
```
### [Summary](https://doc.rust-lang.org/book/ch07-05-separating-modules-into-different-files.html#summary)
- package > crate > module
- refer to items by absolute/relative paths
- `use` paths
- `pub` items (private by default)
# 8. [Common Collections](https://doc.rust-lang.org/book/ch08-00-common-collections.html)
- *collection*
* contains multiple values
* on the heap -- unknown amount, can grow or shrink
* each kind has different capabilities and costs
- these are *vector*, *string*, *hash map* and [more...](https://doc.rust-lang.org/std/collections)
## 8.1. [Storing Lists of Values with Vectors](https://doc.rust-lang.org/book/ch08-01-vectors.html)
- *vector* -- `Vec<T>`
* store values of the same type
* for a list of items
### [Creating a New Vector](https://doc.rust-lang.org/book/ch08-01-vectors.html#creating-a-new-vector)
- by `Vec::new` function
```rust
let v: Vec<i32> = Vec::new();
```
* a type annotation required
* *generics* can hold any type
- by `vec!` macro (with initial values)
```rust
let v = vec![1, 2, 3];
```
* the type can be inferred
### [Updating a Vector](https://doc.rust-lang.org/book/ch08-01-vectors.html#updating-a-vector)
```rust
let mut v = Vec::new();
v.push(5);
```
- by `push` method
- `mut` required
- the type can be inferred
### [Dropping a Vector Drops Its Elements](https://doc.rust-lang.org/book/ch08-01-vectors.html#dropping-a-vector-drops-its-elements)
- vector gets dropped when it goes out of scope
* all its contents are also dropped
* can be complicated when introduce references...
### [Reading Elements of Vectors](https://doc.rust-lang.org/book/ch08-01-vectors.html#reading-elements-of-vectors)
- according to the behavior when the element not existed
* `&v[2]` → a reference
+ panic
+ program crashed
* `v.get(2)` → `Option<&T>`
+ not panic
+ returns `None`
- (reference rules) the follows cannot in a same block
* `&v[0]` -- immutable borrow
* `v.push(6)` -- mutable borrow
* why? may allocate bigger space and copy all the data
+ former references become invalid
### [Iterating over the Values in a Vector](https://doc.rust-lang.org/book/ch08-01-vectors.html#iterating-over-the-values-in-a-vector)
- immutable
```rust
let v = vec![1, 2, 3];
for i in &v {
println!("{}", i);
}
```
- mutable
```rust
let mut v = vec![1, 2, 3];
for i in &mut v {
*i += 1;
}
```
* use dereference operator (`*`) to change the referenced value
### [Using an Enum to Store Multiple Types](https://doc.rust-lang.org/book/ch08-01-vectors.html#using-an-enum-to-store-multiple-types)
- can be explicit about what types are allowed
* `match` to ensure every case is handled
- when enums won't work... trait objects → Ch17
- more about vectors → [API document](https://doc.rust-lang.org/std/vec/struct.Vec.html)
## 8.2. [Storing UTF-8 Encoded Text with Strings](https://doc.rust-lang.org/book/ch08-02-strings.html)
- difficult?
* Rust exposes possible errors
* strings are complicated than we think
* UTF-8
- string = a collection of bytes + some useful methods
### [What Is a String?](https://doc.rust-lang.org/book/ch08-02-strings.html#what-is-a-string)
- “string” means...
* string slice `str` (in the core language), and
+ usually in its borrowed form `&str`
+ UTF-8 encoded
* the `String` type (in the standard library)
+ growable, mutable, owned
+ UTF-8 encoded
* both, not just one of above
- other string types
### [Creating a New String](https://doc.rust-lang.org/book/ch08-02-strings.html#creating-a-new-string)
- like `Vec<T>`
- an empty string
```rust
let mut s = String::new();
```
- with initial contents
* `to_string`
```rust
let s = "contents".to_string();
```
* `from`
```rust
let s = String::from("contents")
```
- UTF-8 ok!
### [Updating a String](https://doc.rust-lang.org/book/ch08-02-strings.html#updating-a-string)
#### [Appending to a String with `push_str` and `push`](https://doc.rust-lang.org/book/ch08-02-strings.html#appending-to-a-string-with-push_str-and-push)
- `push_str` -- append a string slice
* we can't print `s2` if its ownership was taken
- `push` -- append a single character
#### [Concatenation with the `+` Operator or the `format!` Macro](https://doc.rust-lang.org/book/ch08-02-strings.html#concatenation-with-the--operator-or-the-format-macro)
- `+` operator
```rust
let s = s1 + &s2;
```
* use `add` (generic) method actually
```rust
fn add(self, s: &str) -> String {
```
+ `&s2` (`&String`) is *coerce*d into `&s2[..]` (`&str`)
+ `s1` is moved by `self` (can no longer be used)
* becomes heavy to add multiple strings → use `format!`
- `format!` macro
```rust
let s = format!("{}-{}-{}", s1, s2, s3);
```
* like `println!`
* doesn't take any ownership
### [Indexing into Strings](https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings)
Rust strings cannot be indexed
#### [Internal Representation](https://doc.rust-lang.org/book/ch08-02-strings.html#internal-representation)
because UTF-8 uses variable-width encoding
#### [Bytes and Scalar Values and Grapheme Clusters! Oh My!](https://doc.rust-lang.org/book/ch08-02-strings.html#bytes-and-scalar-values-and-grapheme-clusters-oh-my)
- 3 ways to look at “नमस्ते” (hello in [Devanagari](https://en.wikipedia.org/wiki/Devanagari))
* 18 bytes
```
[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164, 224, 165, 135]
```
* 6 scalar values
```
['न', 'म', 'स', '्', 'त', 'े']
```
* 4 grapheme clusters (we would call *letter*s)
```
["न", "म", "स्", "ते"]
```
- indexing should take constant time (O(1))
* but walking through is required (to tell how many characters)
### [Slicing Strings](https://doc.rust-lang.org/book/ch08-02-strings.html#slicing-strings)
use ranges with caution -- crash if not a char boundary
### [Methods for Iterating Over Strings]()
- `.bytes()` by bytes
- `.chars()` by scalar values
- by grapheme clusters? not provided by standard library
### [Strings Are Not So Simple](https://doc.rust-lang.org/book/ch08-02-strings.html#strings-are-not-so-simple)
trade-off of complexity
## 8.3. [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html)
- *hash map* -- `HashMap<K, V>`
* map keys of type `K` to values of type `V`
* via *hashing function*
- useful to look up by a key of any type (rather than an index)
- check [the document](https://doc.rust-lang.org/stable/std/collections/struct.HashMap.html) for more information
### [Creating a New Hash Map](https://doc.rust-lang.org/book/ch08-03-hash-maps.html#creating-a-new-hash-map)
- with `new` and `insert`
```rust
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
```
* require to `use` (not often used enough to be included in prelude)
* no build-in macro to construct (have less support)
- with `zip` and `collect`
```rust
use std::collections::HashMap;
let keys = vec![String::from("Blue"), String::from("Yellow")];
let values = vec![10, 50];
let mut scores: HashMap<_, _> =
keys.into_iter().zip(values.into_iter()).collect();
```
* can `collect` into many types of data structures (can't infer)
* underscores for Rust to infer the rest
* 💬 `into_iter` vs `iter`? [stackoverflow](https://stackoverflow.com/questions/34733811)
+ `iter`: iterate by references
+ `iter_mut`: iterate by mutable references
+ `into_iter`: iterate and move items
### [Hash Maps and Ownership](https://doc.rust-lang.org/book/ch08-03-hash-maps.html#hash-maps-and-ownership)
- `insert` keys and values
* types with `Copy` trait (like `i32`): copied into
* owned values (like `String`): moved into
- `insert` references
* must be valid as long as the hash map does → Ch10
### [Accessing Values in a Hash Map](https://doc.rust-lang.org/book/ch08-03-hash-maps.html#accessing-values-in-a-hash-map)
- `.get(&key)` → `Option<&V>`
- iterate
```rust
for (key, value) in &scores {
println!("{}: {}", key, value);
}
```
### [Updating a Hash Map](https://doc.rust-lang.org/book/ch08-03-hash-maps.html#updating-a-hash-map)
- but each key can only have one value
* replace old one
* ignore new one
* combine 2 values
#### [Overwriting a Value](https://doc.rust-lang.org/book/ch08-03-hash-maps.html#overwriting-a-value)
replace by `insert` (if already has the same key)
#### [Only Inserting a Value If the Key Has No Value](https://doc.rust-lang.org/book/ch08-03-hash-maps.html#only-inserting-a-value-if-the-key-has-no-value)
`.entry(&key).or_insert(value)` (an `Entry` enum here)
#### [Updating a Value Based on the Old Value](https://doc.rust-lang.org/book/ch08-03-hash-maps.html#updating-a-value-based-on-the-old-value)
`.entry(&key).or_insert(value)` and update by the returned mutable reference (`&mut V`)
### [Hashing Functions](https://doc.rust-lang.org/book/ch08-03-hash-maps.html#hashing-functions)
- “cryptographically strong” hashing function by default
* secure but not fast
- switch to your own *hasher*
* `BuildHasher` trait → Ch10
* [crates.io](https://crates.io/) has many common hashing algorithms
### [Summary](https://doc.rust-lang.org/book/ch08-03-hash-maps.html#summary)
- exercises
* the mean, median and mode of a list
* pig latin
* employees and departments
- read the document
- next: error handling
# 9. [Error Handling](https://doc.rust-lang.org/book/ch09-00-error-handling.html)
- take action to errors, or compile failed → robust
- 2 categories
* `Result<T, E>` for recoverable
* `panic!` for unrecoverable
* no exception in Rust
- recover, or stop execution?
## 9.1. [Unrecoverable Errors with `panic!`](https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-with-panic.html)
- `panic!` macro
* for things that you can do nothing about it
* executes
+ print a failure message
+ unwind and clean up the stack
+ quit
:::info
### [Unwinding the Stack or Aborting in Response to a Panic](https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-with-panic.html#unwinding-the-stack-or-aborting-in-response-to-a-panic)
- in response to a panic
* *unwinding*
+ clean up the stack (a lot of work)
* *abort*
+ leave it cleaned by OS
+ smaller binary
- in *Cargo.toml*
```rust
[profile.release]
panic = 'abort'
```
:::
- the error messages
* the panic message
* where the panic occurred
+ might be in other's code
+ use the backtrace to figure out...
### [Using a `panic!` Backtrace](https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-with-panic.html#using-a-panic-backtrace)
- example: access the 100th element of a vector has only 3 elements
* in C, undefined behavior (*buffer overread*) → security vulnerabilities
* in Rust, stop execution
- set `RUST_BACKTRACE` environment variable to get backtraces
* from the top and read until the file you wrote
* debug symbols must be enabled -- `cargo build`/`cargo run` without `--release`
## 9.2. [Recoverable Errors with `Result`](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)
- to do something about errors
- `Result` enum
```rust
enum Result<T, E> {
Ok(T),
Err(E),
}
```
* generic type parameters for different situations
- `File::open` returns what?
* read the [document](https://doc.rust-lang.org/std/fs/struct.File.html#method.open)
* ask the compiler -- give a wrong type annotation, then compile
+ `std::result::Result<std::fs::File, std::io::Error>`
- use `match` to handle the `Result`
* `Ok` and `Err` are already in prelude (like `Option`)
### [Matching on Different Errors](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#matching-on-different-errors)
- create the file when it doesn't exist
* `error.kind()` to get an `io::ErrorKind` (`match ErrorKind::NotFound`)
* `File::create` could also fail (`match Err(error)`)
- lots of `match`? `result.unwarp_or_else()` + closures → Ch13
* 💬 unwarp `Ok` for `T`, or else handle `Err` by `E`
### [Shortcuts for Panic on Error: `unwrap` and `expect`](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#shortcuts-for-panic-on-error-unwrap-and-expect)
- helper methods of `Result`
* `unwrap`
+ `Ok`: return the value
+ `Err`: `panic!`
* `expect`
+ same as `unwarp` but use our error message
### [Propagating Errors](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#propagating-errors)
- pass the error to the caller (may have more information)
- example
* return type: `Result<String, io::Error>` 💬 `io::Error` rely on implementation?
* `File::open`
+ `Ok`: continue with `f`
+ `Err`: <code><del>panic!</del></code> `return Err(e)`
* `f.read_to_string`
+ `Ok`: `Ok(s)`
+ `Err`: `Err(e)`
+ (ending expression) implicitly returned
* let caller handle it
#### [A Shortcut for Propagating Errors: the `?` Operator](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator)
- almost the same as the `match` above
* `Ok`: return value from expression
* `Err`: return error from function
* but go through `from` to convert error type
* finally `Ok(s)`
- shorten
* chain method calls
* `File::open("hello.txt")`
#### [The `?` Operator Can Be Used in Functions That Return Result](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#the--operator-can-be-used-in-functions-that-return-result)
- `?` operator is only allowed in a function returns...
* `Result`
* `Option`
* `std::ops::Try`
- main's return type must be
* `()`
* `Result<T, E>` -- `Result<(), Box<dyn Error>>`
## 9.3. [To `panic!` or Not to `panic!`](https://doc.rust-lang.org/book/ch09-03-to-panic-or-not-to-panic.html)
a good default -- return `Result` and let caller decide it
### [Examples, Prototype Code, and Tests](https://doc.rust-lang.org/book/ch09-03-to-panic-or-not-to-panic.html#examples-prototype-code-and-tests)
- use `unwrap` and `expect`
* to illustrate the key point
* as good placeholders when prototyping
* to fail tests
### [Cases in Which You Have More Information Than the Compiler](https://doc.rust-lang.org/book/ch09-03-to-panic-or-not-to-panic.html#cases-in-which-you-have-more-information-than-the-compiler)
- you know `Err` will not happen (such as hard-coding)
### [Guidelines for Error Handling](https://doc.rust-lang.org/book/ch09-03-to-panic-or-not-to-panic.html#guidelines-for-error-handling)
- becoming in a bad state → `panic!`
- bad states
* assumption has been broken
* not expected to happen occasionally
* rely on not being in the bad state
* not a good way to encode this
- when you have no way to fix → `panic!`
- when failure is expected → return a `Result`
- `panic!` for safety reasons
- annoying? use type system
### [Creating Custom Types for Validation](https://doc.rust-lang.org/book/ch09-03-to-panic-or-not-to-panic.html#creating-custom-types-for-validation)
- check every time → not good
- define a `Guess` type 💬 to encapsulation
* `::new()` ensure the value is valid
* `.value()` return the value (read-only)
### [Summary](https://doc.rust-lang.org/book/ch09-03-to-panic-or-not-to-panic.html#summary)
- properly use...
* `panic!` to stop instead of proceed
* `Result` to tell caller it could recover
- next: generics
# 10. [Generic Types, Traits, and Lifetimes](https://doc.rust-lang.org/book/ch10-00-generics.html)
- *generic*: express behavior without concrete types
* such as `Option<T>`, `Vec<T>`, `HashMap<K, V>`, `Result<T, E>`
* now define your own
- in this chapter
* reduce duplication (without/with *generic*)
* *trait*
* *lifetime*
### [Removing Duplication by Extracting a Function](https://doc.rust-lang.org/book/ch10-00-generics.html#removing-duplication-by-extracting-a-function)
- remove duplication without generic first
- example: largest number
* have to update the code in multiple places
* define a function to express the concept abstractly
- steps
1. identify
2. extract
3. replace
## 10.1. [Generic Data Types](https://doc.rust-lang.org/book/ch10-01-syntax.html)
define functions, structs, enums, methods using generics
### [In Function Definitions](https://doc.rust-lang.org/book/ch10-01-syntax.html#in-function-definitions)
- example: `largest_i32`, `largest_char` → `largest<T>`
* `T` for type (convention)
* declare parameters and return type
* compile error: `T` might need a bound for `std::cmp::PartialOrd`
+ trait
### [In Struct Definitions](https://doc.rust-lang.org/book/ch10-01-syntax.html#in-struct-definitions)
- example
```rust
struct Point<T> {
x: T,
y: T,
}
```
* both `x` and `y` should be the same type `T`
+ otherwise, use multiple generic types
+ however, too many may hard to read
### [In Enum Definitions](https://doc.rust-lang.org/book/ch10-01-syntax.html#in-enum-definitions)
- example: `Option<T>`
- example: `Result<T, E>`
### [In Method Definitions](https://doc.rust-lang.org/book/ch10-01-syntax.html#in-method-definitions)
- use existing types
```rust
impl<T> Point<T> {
fn x(&self) -> &T { … }
}
```
- only for `Point<f32>`
```rust
impl Point<f32> {
fn distance(&self) -> &f32 { … }
}
```
- use different types
```rust
impl<T, U> Point<T, U> {
fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> { … }
}
```
### [Performance of Code Using Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html#performance-of-code-using-generics)
*monomorphization* at compile time → no run-time cost
## 10.2 [Traits: Defining Shared Behavior](https://doc.rust-lang.org/book/ch10-02-traits.html)
- *trait*: describe functionality between types
* similar to *interface*
### [Defining a Trait](https://doc.rust-lang.org/book/ch10-02-traits.html#defining-a-trait)
- to group required method signatures for some purpose
- example
```rust
pub trait Summary {
fn summarize(&self) -> String;
}
```
* each type with this trait must provide the implementation (compiler check)
* can have multiple methods
### [Implementing a Trait on a Type](https://doc.rust-lang.org/book/ch10-02-traits.html#implementing-a-trait-on-a-type)
- similar to regular methods
```rust
impl Summary for Tweet {
fn summarize(&self) -> String { … }
}
```
* thus `tweet.summarize()` can be called
- restrictions
* bring the trait into scope
* while the trait should be `pub`
* the trait or the type is local to our crate
+ *coherence* (*orphan rule*): implement the same trait for the same type only once
### [Default Implementations](https://doc.rust-lang.org/book/ch10-02-traits.html#default-implementations)
- so as to keep/overwrite the default behavior
- leave `impl Summary for NewArticle {}` empty (not to override)
* `article.summarize()` can be called
- having a default implementation doesn't change the one already override
- can call other methods in the same trait
* useful to customize just a small part
### [Traits as Parameters](https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters)
- accept many different types
```rust
pub fn notify(item: &impl Summary) { … }
```
#### [Trait Bound Syntax](https://doc.rust-lang.org/book/ch10-02-traits.html#trait-bound-syntax)
- syntax sugar: longer but more verbose
- force arguments be the same type
```rust
pub fn notify<T: Summary>(item1: &T, item2: &T) { … }
```
#### [Specifying Multiple Trait Bounds with the `+` Syntax](https://doc.rust-lang.org/book/ch10-02-traits.html#specifying-multiple-trait-bounds-with-the--syntax)
```rust
pub fn notify(item: &(impl Summary + Display)) { … }
```
```rust
pub fn notify<T: Summary + Display>(item: &T) { … }
```
#### [Clearer Trait Bounds with `where` Clauses](https://doc.rust-lang.org/book/ch10-02-traits.html#clearer-trait-bounds-with-where-clauses)
```rust
fn function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 { … }
```
```rust
fn function<T, U>(t: &t, u: &U) -> i32
where T: Display + Clone, U: Clone + Debug
{
```
### [Returning Types that Implement Traits](https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits)
- for types that
* only the compiler knows -- closures
* very long to specify -- iterators
- returning different types is not allowed → Ch17
### [Fixing the `largest` Function with Trait Bounds](https://doc.rust-lang.org/book/ch10-02-traits.html#fixing-the-largest-function-with-trait-bounds)
- to compare: `PartialOrd`
- to copy: `Copy`
* not to copy
+ use `Clone` (slow)
+ use references
### [Using Trait Bounds to Conditionally Implement Methods](https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods)
- only `Display + PartialOrd` of `Pair<T>` has `cmp_display()`
- *blanket*: implement a trait for any type that satisfies the trait bounds 💬 ?
## 10.3. [Validating References with Lifetimes](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html)
- generic lifetime parameter: have to annotate *lifetime* in some cases
* most of the time, *lifetime*s of references are implicit and inferred (just like types)
### [Preventing Dangling References with Lifetimes](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#preventing-dangling-references-with-lifetimes)
borrow the value from the inner scope → won't compile: not live long enough
### [The Borrow Checker](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#the-borrow-checker)
*borrow checker* checks lifetimes to ensure all borrows are valid
### [Generic Lifetimes in Functions](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#generic-lifetimes-in-functions)
- a function borrows 2 values, then return one of them → won't compile
* we don't know the lifetime of which will be taken
* solution: generic lifetime parameters
### [Lifetime Annotation Syntax](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#lifetime-annotation-syntax)
- limit relationships between references that a function can accept
```rust
&'a i32
```
* no lifetime will be changed
* relationship: one lifetime annotation by itself -- does not have much meaning
### [Lifetime Annotations in Function Signatures](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#lifetime-annotations-in-function-signatures)
- to fix the function by lifetime annotations
```rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { … }
```
* constraint: all the parameters and the return value -- have the same lifetime `'a`
* `'a` is inferred as the smallest one that passed in
* borrow checker disallows any possibility having invalid references
### [Thinking in Terms of Lifetimes](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#thinking-in-terms-of-lifetimes)
- specify lifetime parameters depends on what your function is doing
- if the lifetime parameter for the return type doesn't match the one of any parameter
* thus, it must refer to a value within the function → won't compile
### [Lifetime Annotations in Struct Definitions](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#lifetime-annotations-in-struct-definitions)
add a lifetime annotation on every reference in the definition
```rust
struct ImportantExcerpt<'a> {
part: &'a str,
}
```
### [Lifetime Elision](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#lifetime-elision)
- history: functions without lifetime annotation
* before (Rust pre-1.0): every reference do need an explicit lifetime
* same predictable/deterministic patterns appear
* let borrow checker infer it
* more patterns may be found in the future
- lifetimes of references
* lifetimes of function/method parameters -- *input lifetime*s
* lifetimes of return values -- *output lifetime*s
- *litetime elision rules*
1. each reference parameter gets its own lifetime parameter
2. exactly one input lifetime parameter `'a`
→ all output lifetime parameters: `'a`
3. one of them is `&self` or `&mut self`
→ all output lifetime parameters: the lifetime of `self`
- after all rules, still can't figure out the lifetime of any reference → error
- example
* exactly one
* more then one, and not method
### [Lifetime Annotations in Method Definitions](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#lifetime-annotations-in-method-definitions)
- syntax: as generic type parameters
```rust
impl<'a> ImportantExcerpt<'a> {
fn announce_and_return_part(&self, announcement: &str) -> &str { … }
}
```
* annotation of `&self` is not required -- 1st rule
* annotation of return type is not required -- 3rd rule
### [The Static Lifetime](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#the-static-lifetime)
- `'static`
* all string literals have `'static` lifetime
* usually not required
### [Generic Type Parameters, Trait Bounds, and Lifetimes Together](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#generic-type-parameters-trait-bounds-and-lifetimes-together)
an overall example
### [Summary](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#summary)
- review
* generic type parameters
* traits and trait bounds
* lifetime annotations
- more to learn → Ch17
{%hackmd @yipo/S1Hes0jTd %}