Compare commits

...

27 Commits

Author SHA1 Message Date
732235ab69 finsihed The Rust Programming Language Bookgit add -Agit add -A
All checks were successful
Test Gitea Actions / first (push) Successful in 21s
Test Gitea Actions / check-code (push) Successful in 17s
Test Gitea Actions / test (push) Successful in 17s
Test Gitea Actions / documentation-check (push) Successful in 16s
2025-04-18 16:14:55 -06:00
ff4c4fccee finished ch20.5 and ch20 WHOOH
All checks were successful
Test Gitea Actions / first (push) Successful in 20s
Test Gitea Actions / check-code (push) Successful in 16s
Test Gitea Actions / test (push) Successful in 16s
Test Gitea Actions / documentation-check (push) Successful in 17s
2025-04-17 16:09:28 -06:00
4274106509 started ch20.5
All checks were successful
Test Gitea Actions / first (push) Successful in 20s
Test Gitea Actions / check-code (push) Successful in 16s
Test Gitea Actions / test (push) Successful in 16s
Test Gitea Actions / documentation-check (push) Successful in 16s
2025-04-17 12:50:58 -06:00
e6bb4977b8 almost finished ch20.4
All checks were successful
Test Gitea Actions / first (push) Successful in 21s
Test Gitea Actions / check-code (push) Successful in 16s
Test Gitea Actions / test (push) Successful in 19s
Test Gitea Actions / documentation-check (push) Successful in 19s
2025-04-16 17:13:02 -06:00
e73197aa26 finished ch20.3 2025-04-16 15:44:05 -06:00
0c0dcfee81 finished ch20.2 2025-04-15 17:03:30 -06:00
5da2a5c2b5 finished ch20.1
All checks were successful
Test Gitea Actions / first (push) Successful in 19s
Test Gitea Actions / check-code (push) Successful in 15s
Test Gitea Actions / test (push) Successful in 16s
Test Gitea Actions / documentation-check (push) Successful in 15s
2025-04-15 12:33:04 -06:00
6aa4deab15 started ch20.1
All checks were successful
Test Gitea Actions / first (push) Successful in 32s
Test Gitea Actions / check-code (push) Successful in 15s
Test Gitea Actions / test (push) Successful in 15s
Test Gitea Actions / documentation-check (push) Successful in 15s
2025-04-14 17:18:50 -06:00
848e5c4e33 finished ch20 intro
All checks were successful
Test Gitea Actions / first (push) Successful in 20s
Test Gitea Actions / check-code (push) Successful in 18s
Test Gitea Actions / test (push) Successful in 18s
Test Gitea Actions / documentation-check (push) Successful in 17s
2025-04-11 11:26:46 -06:00
295d603cbd finished ch19.3 and ch19
All checks were successful
Test Gitea Actions / first (push) Successful in 16s
Test Gitea Actions / check-code (push) Successful in 16s
Test Gitea Actions / test (push) Successful in 16s
Test Gitea Actions / documentation-check (push) Successful in 15s
2025-04-10 16:47:49 -06:00
730b0091e8 finished ch19.2 and started ch19.3
All checks were successful
Test Gitea Actions / first (push) Successful in 21s
Test Gitea Actions / check-code (push) Successful in 18s
Test Gitea Actions / test (push) Successful in 18s
Test Gitea Actions / documentation-check (push) Successful in 17s
2025-04-09 17:00:42 -06:00
f0cbfdf024 finished ch19.1
All checks were successful
Test Gitea Actions / first (push) Successful in 17s
Test Gitea Actions / check-code (push) Successful in 17s
Test Gitea Actions / test (push) Successful in 18s
Test Gitea Actions / documentation-check (push) Successful in 18s
2025-04-08 16:00:21 -06:00
c3ea7d26e3 finished ch19 intro 2025-04-08 11:54:40 -06:00
849d24a10b finished ch18.3 and ch18
All checks were successful
Test Gitea Actions / first (push) Successful in 22s
Test Gitea Actions / check-code (push) Successful in 17s
Test Gitea Actions / test (push) Successful in 16s
Test Gitea Actions / documentation-check (push) Successful in 16s
2025-04-07 16:56:06 -06:00
35fda43f47 75% done ch18.3 2025-04-07 14:35:07 -06:00
070680441b fixed workflow
All checks were successful
Test Gitea Actions / first (push) Successful in 15s
Test Gitea Actions / check-code (push) Successful in 14s
Test Gitea Actions / test (push) Successful in 16s
Test Gitea Actions / documentation-check (push) Successful in 17s
2025-04-03 22:56:23 -06:00
7118958a77 started ch 18.3
Some checks failed
Test Gitea Actions / first (push) Successful in 28s
Test Gitea Actions / check-code (push) Failing after 28s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-04-03 17:01:38 -06:00
559d4bcdef finished 18.2 2025-04-03 13:09:01 -06:00
cb2ac6ab69 removed old dead code
Some checks failed
Test Gitea Actions / first (push) Successful in 16s
Test Gitea Actions / check-code (push) Failing after 15s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-04-02 16:17:36 -06:00
5ab5d5105e fixing github actions 2025-04-02 16:16:03 -06:00
cd63c9fd53 attempted fix to github actions 2025-04-02 16:06:58 -06:00
3c3c5cf67b finished ch18.1 2025-04-02 15:37:00 -06:00
dbdd3d8d07 started ch18.1
Some checks failed
Test Gitea Actions / first (push) Successful in 23s
Test Gitea Actions / check-code (push) Failing after 18s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-04-01 16:47:10 -06:00
665215bd19 finished ch17.6 and ch18 intro
Some checks failed
Test Gitea Actions / first (push) Successful in 14s
Test Gitea Actions / check-code (push) Failing after 13s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-31 16:32:24 -06:00
1092bec5ad Merge branch 'master' of github.com:darkicewolf50/RustBrock 2025-03-31 14:56:54 -06:00
97fdc130c3 Merge branch 'master' of github.com:darkicewolf50/RustBrock 2025-03-31 14:56:30 -06:00
c1bdb1043e finished ch17.5 2025-03-31 14:55:57 -06:00
29 changed files with 5081 additions and 270 deletions

View File

@ -3,9 +3,8 @@
name: Test Gitea Actions
# events that will trigger this workflow.
# here, we only have "pull_request", so the workflow will run
# whenever we create a pull request.
# other examples: [push] and [pull_request, push]
# here, we only have "push", so the workflow will run
# whenever we push code to the repository.
on: [push]
env:
@ -17,111 +16,63 @@ env:
jobs:
# name of the job
first:
# the platform or OS that the workflow will run on.
runs-on: ubuntu-latest
# series of steps to finish the job.
steps:
# name of the step.
# steps run sequentially.
# this is optionale
- name: checkout
# each step can either have "uses" or "run".
# "uses" run an action written somewhere other than this workflow .
# usually from the community.
# this action checks out the repo code to the runner (instance)
# running the action
uses: actions/checkout@v3
# another step.
# this step runs a bash (Ubuntu's default shell) command
- name: list files
run: ls
# name of the job
check-code:
# the platform or OS that the workflow will run on.
runs-on: ubuntu-latest
# series of steps to finish the job.
steps:
# name of the step.
# steps run sequentially.
# this is optionale
- name: checkout
# each step can either have "uses" or "run".
# "uses" run an action written somewhere other than this workflow .
# usually from the community.
# this action checks out the repo code to the runner (instance)
# running the action
uses: actions/checkout@v4
- name: move to minigrep
run: cd minigrep/
# another step.
# Step 1: Run cargo check and fail if it fails
- name: Check
run: cargo check --verbose
steps:
- name: checkout
uses: actions/checkout@v4
# Step 1: Move to minigrep directory and list files to debug
# - name: Move to minigrep and list files
# run: |
# cd minigrep/
# ls -la # This will list the contents of the minigrep directory to ensure it's correct
- name: Check
run: |
cd minigrep/ # Make sure we're in the correct directory
cargo check --verbose
# name of the job
test:
# the platform or OS that the workflow will run on.
runs-on: ubuntu-latest
# Ensures this job runs only if check-code succeeds
needs: check-code
# series of steps to finish the job.
steps:
# name of the step.
# steps run sequentially.
# this is optionale
- name: checkout
# each step can either have "uses" or "run".
# "uses" run an action written somewhere other than this workflow .
# usually from the community.
# this action checks out the repo code to the runner (instance)
# running the action
uses: actions/checkout@v4
- name: move to minigrep
run: cd minigrep/
# Step 2: Run unit and integration tests (excluding documentation tests)
- name: Run Tests
run: cargo test --tests --verbose
needs: check-code
steps:
- name: checkout
uses: actions/checkout@v4
- name: Run Tests
run: |
cd minigrep/
cargo test --tests --verbose
# name of the job
documentation-check:
# the platform or OS that the workflow will run on.
runs-on: ubuntu-latest
# Ensures this job runs only if check-code succeeds
needs: check-code
# series of steps to finish the job.
needs: check-code
steps:
# name of the step.
# steps run sequentially.
# this is optionale
- name: checkout
# each step can either have "uses" or "run".
# "uses" run an action written somewhere other than this workflow .
# usually from the community.
# this action checks out the repo code to the runner (instance)
# running the action
uses: actions/checkout@v4
- name: checkout
uses: actions/checkout@v4
- name: move to minigrep
run: cd minigrep/
# Step 3: Check if documentation tests were run
- name: Check for Documentation Tests
run: |
DOC_TESTS=$(cargo test --doc --verbose)
if [[ ! "$DOC_TESTS" =~ "running" ]]; then
echo "No documentation tests were run!" && exit 1
fi
- name: Check for Documentation Tests
run: |
cd minigrep/
DOC_TESTS=$(cargo test --doc --verbose)
if [[ ! "$DOC_TESTS" =~ "running" ]]; then
echo "No documentation tests were run!" && exit 1
fi

View File

@ -1,11 +1,10 @@
# name of the workflow.
# this is optional.
name: Test Gitea Actions
name: Test Rust Actions
# events that will trigger this workflow.
# here, we only have "pull_request", so the workflow will run
# whenever we create a pull request.
# other examples: [push] and [pull_request, push]
# here, we only have "push", so the workflow will run
# whenever we push code to the repository.
on: [push]
env:
@ -17,111 +16,63 @@ env:
jobs:
# name of the job
first:
# the platform or OS that the workflow will run on.
runs-on: ubuntu-latest
# series of steps to finish the job.
steps:
# name of the step.
# steps run sequentially.
# this is optionale
- name: checkout
# each step can either have "uses" or "run".
# "uses" run an action written somewhere other than this workflow .
# usually from the community.
# this action checks out the repo code to the runner (instance)
# running the action
uses: actions/checkout@v3
# another step.
# this step runs a bash (Ubuntu's default shell) command
- name: list files
run: ls
# name of the job
check-code:
# the platform or OS that the workflow will run on.
runs-on: ubuntu-latest
# series of steps to finish the job.
steps:
# name of the step.
# steps run sequentially.
# this is optionale
- name: checkout
# each step can either have "uses" or "run".
# "uses" run an action written somewhere other than this workflow .
# usually from the community.
# this action checks out the repo code to the runner (instance)
# running the action
uses: actions/checkout@v4
- name: move to minigrep
run: cd minigrep/
# another step.
# Step 1: Run cargo check and fail if it fails
- name: Check
run: cargo check --verbose
steps:
- name: checkout
uses: actions/checkout@v4
# Step 1: Move to minigrep directory and list files to debug
# - name: Move to minigrep and list files
# run: |
# cd minigrep/
# ls -la # This will list the contents of the minigrep directory to ensure it's correct
- name: Check
run: |
cd minigrep/ # Make sure we're in the correct directory
cargo check --verbose
# name of the job
test:
# the platform or OS that the workflow will run on.
runs-on: ubuntu-latest
# Ensures this job runs only if check-code succeeds
needs: check-code
# series of steps to finish the job.
steps:
# name of the step.
# steps run sequentially.
# this is optionale
- name: checkout
# each step can either have "uses" or "run".
# "uses" run an action written somewhere other than this workflow .
# usually from the community.
# this action checks out the repo code to the runner (instance)
# running the action
uses: actions/checkout@v4
- name: move to minigrep
run: cd minigrep/
# Step 2: Run unit and integration tests (excluding documentation tests)
- name: Run Tests
run: cargo test --tests --verbose
needs: check-code
steps:
- name: checkout
uses: actions/checkout@v4
- name: Run Tests
run: |
cd minigrep/
cargo test --tests --verbose
# name of the job
documentation-check:
# the platform or OS that the workflow will run on.
runs-on: ubuntu-latest
# Ensures this job runs only if check-code succeeds
needs: check-code
# series of steps to finish the job.
needs: check-code
steps:
# name of the step.
# steps run sequentially.
# this is optionale
- name: checkout
# each step can either have "uses" or "run".
# "uses" run an action written somewhere other than this workflow .
# usually from the community.
# this action checks out the repo code to the runner (instance)
# running the action
uses: actions/checkout@v4
- name: checkout
uses: actions/checkout@v4
- name: move to minigrep
run: cd minigrep/
# Step 3: Check if documentation tests were run
- name: Check for Documentation Tests
run: |
DOC_TESTS=$(cargo test --doc --verbose)
if [[ ! "$DOC_TESTS" =~ "running" ]]; then
echo "No documentation tests were run!" && exit 1
fi
- name: Check for Documentation Tests
run: |
cd minigrep/
DOC_TESTS=$(cargo test --doc --verbose)
if [[ ! "$DOC_TESTS" =~ "running" ]]; then
echo "No documentation tests were run!" && exit 1
fi

View File

@ -1,5 +1,5 @@
{
"collapse-filter": true,
"collapse-filter": false,
"search": "",
"showTags": false,
"showAttachments": false,
@ -18,5 +18,5 @@
"linkStrength": 1,
"linkDistance": 250,
"scale": 0.8410178518902366,
"close": false
"close": true
}

View File

@ -8,129 +8,73 @@
"type": "tabs",
"children": [
{
"id": "caf0233e624d6c1c",
"id": "de2ac5df5b921166",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Test Controls.md",
"file": "Advanced Features.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Test Controls"
"title": "Advanced Features"
}
},
{
"id": "53b36d00b704136e",
"id": "0cdb5cb65c12cd29",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Concurrency.md",
"file": "Macros.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Concurrency"
"title": "Macros"
}
},
{
"id": "42d65c7d3f15198d",
"id": "8efdb57e394f2650",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Async, Await, Futures and Streams.md",
"file": "Advanced Traits.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Async, Await, Futures and Streams"
"title": "Advanced Traits"
}
},
{
"id": "6142f6650517896f",
"id": "74db89a42def0b8b",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Any Number of Futures.md",
"file": "Advanced Types.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Any Number of Futures"
"title": "Advanced Types"
}
},
{
"id": "8d868fd701da33a8",
"id": "8cdde5c4be386d20",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Futures in Sequence.md",
"file": "Unsafe Rust.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Futures in Sequence"
}
},
{
"id": "ee4116419493acd3",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Traits for Async.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Traits for Async"
}
},
{
"id": "2a974ca5442d705f",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Sync and Send.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Sync and Send"
}
},
{
"id": "3d0ca0b1691c4c2f",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Shared State Concurrency.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Shared State Concurrency"
}
},
{
"id": "b104e4647c0ac328",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Leaky Reference Cycles.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Leaky Reference Cycles"
"title": "Unsafe Rust"
}
},
{
@ -143,8 +87,7 @@
"title": "Graph view"
}
}
],
"currentTab": 5
]
}
],
"direction": "vertical"
@ -287,10 +230,26 @@
"command-palette:Open command palette": false
}
},
"active": "ee4116419493acd3",
"active": "de2ac5df5b921166",
"lastOpenFiles": [
"Futures in Sequence.md",
"Macros.md",
"Advanced Features.md",
"Advanced Functions and Closures.md",
"Advanced Traits.md",
"Advanced Types.md",
"Enums.md",
"Unsafe Rust.md",
"Pattern Matching.md",
"Places Patterns Can Be Used.md",
"Pattern Syntax.md",
"Refutability.md",
"Implementing OO Design Pattern.md",
"Trait Objects that allow for Values of Different Types.md",
"Characteristics of OO Languages.md",
"OOP Programming Features.md",
"Futures, Tasks and Threads Together.md",
"Traits for Async.md",
"Futures in Sequence.md",
"Any Number of Futures.md",
"Futures and Async.md",
"Async, Await, Futures and Streams.md",
@ -299,23 +258,7 @@
"Sync and Send.md",
"().md",
"Smart Pointers.md",
"Simultaneous Code Running.md",
"Passing Data Between Threads.md",
"Leaky Reference Cycles.md",
"Test Controls.md",
"Ref Cell Mutability.md",
"Reference Counter Smart Pointer.md",
"The Performance Closures and Iterators.md",
"Improving The IO Project.md",
"Tests.md",
"The Preformance Closures and Iterators.md",
"minigrep/README.md",
"Project Organization.md",
"Writing_Tests.md",
"minigrep/src/lib.rs",
"Test_Organization.md",
"Traits.md",
"Modules and Use.md",
"does_not_compile.svg",
"Untitled.canvas",
"Good and Bad Code/Commenting Pratices",

26
Advanced Features.md Normal file
View File

@ -0,0 +1,26 @@
# Advanced Features
So far we learned about the most commonly used parts of the Rust programming language.
Here we will look at a few aspects of the language you may run into once in a while but may not use everyday.
This is intended to be used as a reference for when you encounter any unknowns.
The features covered here are useful in very specific situations.
In this chapter we will cover
- [Unsafe Rust](./Unsafe%20Rust.md): How to opt out of some of Rust's guarantees and take responsibility for manually upholding those guarantees
- [Advanced traits](./Advanced%20Traits.md): associated types, default type parameters, fully qualified syntax, supertraits, and the new type pattern in relation to traits
- [Advanced types](./Advanced%20Types.md): more about the newtype pattern, type aliases, the never type, and dynamically sized types
- [Advanced functions and closures](./Advanced%20Functions%20and%20Closures.md): function pointers and returning closures
- [Macros](./Macros.md): ways to define code that defines more code at compile time
## Summary
These are great tools to have in your toolbox that you like likely not use often.
Knowing that they are available is very valuable.
The complex topics introduced are useful for when you encounter them in error messages in other people's code.
So you will be able to recognize the concepts and syntax.
Use this chapter as a reference to guide you solutions.

View File

@ -0,0 +1,145 @@
# Advanced Functions and Closures
This section includes some more advanced features including function pointers and returning closures.
## Function Pointers
We have talked about how to pass closures to functions; you can also pass regular functions to functions.
This technique is useful when you want to pass a function that you have already defined rather than defining a new closure.
Functions coerce to the type `fn` (with a lowercase f), not to be confused with, not to be confused with the `Fn` closure trait.
The `fn` type is called a *function pointer*.
Passing function pointers will allow you to use functions as arguments to other functions.
The syntax for specifying that a parameter is a function pointer is similar to that of closures as shown below.
This shows that we have defined a function `add_one` that adds one to its parameter.
The function `do_twice` takes two parameters: a function pointer to any function takes an `i32` parameter and returns an `i32`, and one `i32` value.
The `do_twice` function calls the function `f` twice, passing it the `arg` value, then adds the two function call results together.
The `main` function calls `do_twice` with the arguments `add_one` and `5`.
```rust
fn add_one(x: i32) -> i32 {
x + 1
}
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
f(arg) + f(arg)
}
fn main() {
let answer = do_twice(add_one, 5);
println!("The answer is: {answer}");
}
```
Output
```
The answer is: 12
```
Here we specify that the parameter `f` in `do_twice` is an `fn` that takes one parameter of type `i32` and returns a `i32`.
We can then call `f` from the body of `do_twice`.
In `main` we can pass the function name `add_one` as the first arg to `do_twice`.
Unlike closures, `fn` is a type rather than a trait, so we need to specify `fn` as the parameter type directly rather than declaring a generic type parameter with one of the `Fn` traits as a trait bound.
Function pointers implement all three of the closure traits (`Fn`, `FnMut` and `FnOnce`).
This means that you can always pass a function pointer as an argument for a function that expects a closure.
It is best to write functions using a generic type and one of the closure traits so your functions can accept either functions or closures.
That being said, one example of where you would only want to accept `fn` and not closures is when interfacing with external code that doesn't have closures.
C functions can accept functions as arguments, but C doesn't have closures.
As an example of where you could use either a closure defined inline or a named function.
Lets look at a use of the `map` method provided by the `Iterator` trait in the std library.
To use the `map` function to turn a vector of numbers into a vector of strings, we could use a closure.
Like this:
```rust
let list_of_numbers = vec![1, 2, 3];
let list_of_strings: Vec<String> =
list_of_numbers.iter().map(|i| i.to_string()).collect();
```
We could have a function as the argument to `map` instead of the closure.
Like this:
```rust
let list_of_numbers = vec![1, 2, 3];
let list_of_strings: Vec<String> =
list_of_numbers.iter().map(ToString::to_string).collect();
```
Note, we must use the fully qualified syntax that we talked about earlier in ["Advanced Traits"](./Advanced%20Traits.md) section.
This is because there are multiple functions available named `to_string`.
Here we are using the `to_string` function defined in the `ToString` trait, which is in the std library has implemented for any type that implements `Display`.
Recall form the ["Enum values"]() section of Ch6 that the name of each enum variant that we define also becomes an initializer function.
We can use these initializer functions as function pointers that implement the closure traits, this means we can specify the initializer functions as arguments for methods that take closures.
Like this:
```rust
enum Status {
Value(u32),
Stop,
}
let list_of_statuses: Vec<Status> = (0u32..20).map(Status::Value).collect();
```
Here we creates `Status::Value` instances using each `u32` value in the range that `map` is called on by using the initializer function of `Status::Value`.
Some prefer to use this style, and some people prefer to use closures.
They compile to the same code, so use whatever style is clearer to you.
## Returning Closures
Closures are represented by traits, meaning that you can't return closures directly.
In cases where you want to return a trait, you instead use the concrete type that implements the trait as the return value of the function.
You are unable to do that with closures because they do not have a concrete type that is returnable.
You are not allowed to use the function pointer `fn` as a return type, for example.
Instead, you would normally use the `impl Trait` syntax we learned from Ch10.
You can return any function type using the `Fn`, `FnOnce` and `FnMut`.
This code would work just fine.
```rust
fn returns_closure() -> impl Fn(i32) -> i32 {
|x| x + 1
}
```
As noted in the ["Closure Type Inference and Annotation"](./Closures.md#closure-type-inference-and-annoation) section in Ch13, each closure is also its own distinct type.
If you needed to work with multiple functions that have the same signature but slightly different implementations, you will need to use a trait object for them.
```rust
fn main() {
let handlers = vec![returns_closure(), returns_initialized_closure(123)];
for handler in handlers {
let output = handler(5);
println!("{output}");
}
}
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
Box::new(|x| x + 1)
}
fn returns_initialized_closure(init: i32) -> Box<dyn Fn(i32) -> i32> {
Box::new(move |x| x + init)
}
```
This will compile just fine, but it wouldn't if we had tried to stick with `impl Fn(i32) -> i32`.

542
Advanced Traits.md Normal file
View File

@ -0,0 +1,542 @@
# Advanced Traits
Here we will go into the nitty-gritty of traits..
## Specifying Placeholder Types in Trait Definitions with Associated Types
*Associated types* connect a type placeholder with a trait such that the trait method definitions can use these placeholder types in their signatures.
The implementor of a trait will specify the concrete type to be used instead of the placeholder type for the particular implementation.
This way we can define a trait that uses some types without needing to know exactly what those types are until the trait is implemented.
We have described most of the advanced features in this chapter as being rarely needed.
Associated types are somewhere in the middle: they are used more rarely than features explained in the rest of the book, but more commonly than many of the other features discussed in this chapter.
One example of trait with an associated type is the `Iterator` trait that the std library provides.
The associated type is named `Item` and stands in for the type of the values the type implementing the `Iterator` trait is iterating over.
Here is the definition of the `Iterator` trait.
```rust
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
```
The type `Item` is a placeholder, and the `next` method's definition shows that it will return values of type `Option<Self::Item>`.
Implementors of the `Iterator` trait will specify the concrete type for `Item` and the `next` method will return an `Option` containing a value of that concrete type.
Associated types may seem like a similar concept to generics, in that the latter allow us to define a function without specifying what types it can handle.
To examine the difference between the two, we will look at the implementation of the `Iterator` trait on a type named `Counter` that specifies the `Item` type is `u32`.
```rust
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
// --snip--
```
This syntax seems similar to that of generics.
So why not just define the `Iterator` trait with generics
```rust
pub trait Iterator<T> {
fn next(&mut self) -> Option<T>;
}
```
The differences is that when using generics, we must annotate the types in each implementation.
Because we can also implement `Iterator<String> for Counter` or any other type, we could have multiple implementations of `Iterator` for `Counter`.
This could also be said, when a trait has a generic parameter, it can be implemented for a type multiple times, changing the concrete types of the generic type parameters each time.
When we use the `next` method on `Counter`, we would have to provide type annotations to indicate which implementation of `Iterator` we want to use.
With associated types, we don't need to annotate types because we can't implement a trait on a type multiple times.
In the first definition that uses associated types, we can only choose what the type of `Item` will be once because there can only be one `impl Iterator for Counter`.
We don't have to specify that we want an iterator of `u32` values everywhere that we call `next` on `Counter`.
Associated types also become part of the trait's contract.
Implementors of the trait must also provide a type to stand in for the associated type placeholder.
Associated types often have a name that describes how the type will be used, and documenting the associated type in the API documentation is good practice.
## Default Generic Type Parameters and Operator Overloading
When we use generic type parameters, we can specify a default concrete type for the generic type.
This eliminates the need for implementors of the trait to specify a concrete type if the default type works.
You can specify a default type when declaring a generic type with the `<PlaceholderType=ConcreteType>` syntax.
A good example of a situation where this technique is useful is with *operator overloading*, where you customize the behavior of an operator (such as `+`) in particular situations.
Rust doesn't allow you to create your own operators or overload arbitrary operators.
You can overload the operation and corresponding traits listed in `std::ops` by implementing the traits associated with the operator.
For example here we overload the `+` operator to add two `Point` instances together.
We do this by implementing the `Add` trait on a `Point` struct.
```rust
use std::ops::Add;
#[derive(Debug, Copy, Clone, PartialEq)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Point;
fn add(self, other: Point) -> Point {
Point {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
fn main() {
assert_eq!(
Point { x: 1, y: 0 } + Point { x: 2, y: 3 },
Point { x: 3, y: 3 }
);
}
```
The `add` method adds the `x` values of two `Point` instances and the `y` values of two `Point` instances to create a new `Point`.
The `Add` trait has an associated type named `Output` that determines the type returned from the `add` method.
The default generic type in this code is within the `Add` trait.
Here is its definition
```rust
trait Add<Rhs=Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
```
This should look generally familiar: a trait with one method and an associated type.
The new part is `Rhs=Self`: this syntax is called *default type parameters*.
The `Rhs` generic type parameter (short for "right hand side") defines the type of the `rhs` parameter in the `add` method.
If we didn't specify a concrete type for `Rhs` when we implement the `Add` trait, the type of `Rhs` will default to `Self`, which will be the type we are implementing `Add` on.
When we implemented `Add` for `Point`, we used the default for `Rhs` because we wanted to add two `Point` instances.
Now lets look at an example of implementing the `Add` trait where we want to customize the `Rhs` type rather than using the default.
Here we want two structs `Millimeters` and `MEters`, which hold values in different units.
This thin wrapping of an existing type in another struct is known as the *newtype pattern*, which will be described in more detail in the ["Using the Newtype Pattern to Implement External Traits on External Types"]() section.
We want to add values in millimeters to values in meters and have the implementation of `Add` do the conversion correctly.
We can implement `Add` for `Millimeters` with `Meters` as the `Rhs`.
```rust
use std::ops::Add;
struct Millimeters(u32);
struct Meters(u32);
impl Add<Meters> for Millimeters {
type Output = Millimeters;
fn add(self, other: Meters) -> Millimeters {
Millimeters(self.0 + (other.0 * 1000))
}
}
```
To add `Millimeters` and `Meters`, we specify `impl Add<Meters>` to set the value of the `Rhs` type parameter instead of using the default of `Self`.
You will use default type parameters in two main ways:
- To extend a type without breaking existing code
- To allow customization in specific cases most users won't need
The std library's `Add` trait is an example of the second purpose.
Usually, you will add two like types, but the `Add` trait provides the ability to customize beyond that.
Using a default type parameter in the `Add` trait definition means you don't have to specify the extra parameter most of the time.
A bit of implementation boilerplate isn't needed, making it easier to use the trait.
The first purpose is similar to the second but in reverse.
If you want to add a type parameter to an existing trait, you can give it a default to allow extension of the functionality of the trait without breaking the existing implementation code.
## Fully Qualified Syntax for Disambiguation: Calling Methods with the Same Name
Nothing in Rust prevents a trait from having a method with the same name as another trait's methods.
Nor does Rust prevent you from implementing both traits on one type.
It is also possible to implement a method directly on the type with the same name as methods form traits.
When calling methods with the same name, you need to specify to Rust which one you want to use.
Consider this code where we have defined two traits, `Pilot` and `Wizard`, that both have a method called `fly`.
Then implement both traits on a type `Human` that already has a method named `fly` implemented on it.
Each `fly` method does something different.
```rust
trait Pilot {
fn fly(&self);
}
trait Wizard {
fn fly(&self);
}
struct Human;
impl Pilot for Human {
fn fly(&self) {
println!("This is your captain speaking.");
}
}
impl Wizard for Human {
fn fly(&self) {
println!("Up!");
}
}
impl Human {
fn fly(&self) {
println!("*waving arms furiously*");
}
}
```
When we call `fly` on an instance of `Human`, the compiler defaults to calling the method that is directly implemented on the type.
```rust
fn main() {
let person = Human;
person.fly();
}
```
The output of this code will print `*waving arms furiously*`, showing that Rust called the `fly` method implemented on `Human` directly.
To call the `fly` methods from either the `Pilot` trait or the `Wizard` trait, we need to use more specific syntax to specify which `fly` method we mean.
Here is a demonstration of this syntax,
```rust
fn main() {
let person = Human;
Pilot::fly(&person);
Wizard::fly(&person);
person.fly();
}
```
Specifying the trait name before the method name clarifies to Rust and Us which implementation of `fly` we want to call.
We could also write `Human::fly(&person)` but that us the same as `person.fly()`.
This is also a bit longer to write if we don't need to disambiguate.
Output
```
$ cargo run
Compiling traits-example v0.1.0 (file:///projects/traits-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.46s
Running `target/debug/traits-example`
This is your captain speaking.
Up!
*waving arms furiously*
```
Because `fly` takes a `self` parameter, if we had two *types* that both implement one *trait*, Rust would be able to figure out which implementation of a `trait` to use based on the type of `self`.
Associated function that are not methods do not have a `self` parameter.
When there are multiple types of traits that define non-method functions with the same function name, Rust doesn't always know which type you mean unless you use *fully qualified syntax*.
For example, we here we create a trait for an animal shelter that wants to name all baby dogs *Spot*.
We make an `Animal` trait with an associated non-method function `baby_name`.
The `Animal` trait is implemented for the struct `Dog`, which we also provide an associated non-method function `baby_name` directly.
```rust
trait Animal {
fn baby_name() -> String;
}
struct Dog;
impl Dog {
fn baby_name() -> String {
String::from("Spot")
}
}
impl Animal for Dog {
fn baby_name() -> String {
String::from("puppy")
}
}
fn main() {
println!("A baby dog is called a {}", Dog::baby_name());
}
```
We implement the code for naming all puppies `Spot` in the `baby_name` associated function that is defined on `Dog`.
The `Dog` type also implements the trait `Animal`, which describes characteristics that all animals have.
Baby dogs are called puppies, and that is expressed in the implementation of the `Animal` trait on `Dog` in the `baby_name` function associated with the `Animal` trait.
In `main` we call the `Dog::baby_name` function, which calls the associated function defined on `Dog` directly.
This outputs
```
$ cargo run
Compiling traits-example v0.1.0 (file:///projects/traits-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.54s
Running `target/debug/traits-example`
A baby dog is called a Spot
```
This isn't thew output we wanted.
We want to call the `baby_name` function that is part of the `Animal` trait that we implemented on `Dog` so that it prints `A baby dog is called a puppy`.
The technique of specifying the trait name that we used here doesn't help here.
If we changed `main` to the code below, we get a compiler error.
```rust
fn main() {
println!("A baby dog is called a {}", Animal::baby_name());
}
```
Because `Animal::baby_name` doesn't have a `self` parameter and there could be other types implements the `Animal` trait, Rust can't figure out which implementation of `Animal::baby_name` we want.
We get this compiler error
```
$ cargo run
Compiling traits-example v0.1.0 (file:///projects/traits-example)
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> src/main.rs:20:43
|
2 | fn baby_name() -> String;
| ------------------------- `Animal::baby_name` defined here
...
20 | println!("A baby dog is called a {}", Animal::baby_name());
| ^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
|
help: use the fully-qualified path to the only available implementation
|
20 | println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
| +++++++ +
For more information about this error, try `rustc --explain E0790`.
error: could not compile `traits-example` (bin "traits-example") due to 1 previous error
```
To disambiguate and tell Rust that we want to use the implementation of `Animal` for `Dog` as opposed to the implementation of `Animal` for some other type.
We need to use fully qualified syntax.
Here demonstrates how to use fully qualified syntax
```rust
fn main() {
println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
}
```
Here we provide Rust with a type annotation within the angle brackets.
This indicates we want to call the `baby_name` method from the `Animal` trait as implementation on `Dog` by saying that we want to treat the `Dog` type as an `Animal` for this function call.
Here is the new output
```
$ cargo run
Compiling traits-example v0.1.0 (file:///projects/traits-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.48s
Running `target/debug/traits-example`
A baby dog is called a puppy
```
Here us a fully qualified syntax is defined as follows
```
<Type as Trait>::function(receiver_if_method, next_arg, ...);
```
For associated function that aren't methods, there would not be a `receiver`: there would only be the list of other arguments.
You could use fully qualified syntax everywhere that you call functions or methods.
You are allowed to omit any part of this syntax that Rust can figure out from other information in the program.
You only need to use this this more verbose syntax in cases where there are multiple implementations that use the same name and Rust needs help to identify which implementation you want to call.
## Using Supertraits to Require One Trait's Functionality Within Another Trait
Sometimes you might write a trait definition that depends on another trait.
For a type to implement the first trait, you want to require that type to also implement the second trait.
You would do this so that your trait definition can make use of the associated items of the second trait.
The trait your trait definition is relying on is called a *supertrait* of your trait.
Lets say we want to make an `OutlinePrint` trait with an `outline_print` method that will print a given value formatted so that it is framed in asterisks.
Given that a `Point` struct that implements the std library trait `Display` to result in `(x, y)`.
When we call `outline_print` on a `Point` instance that has `1` for `x` and `3` for `y`, it should print the following
```
**********
* *
* (1, 3) *
* *
**********
```
The implementation of the `outline_print` method we want to use the `Display` trait's functionality.
Therefore we need to specify that the `OutlinePrint` trait will work only for types that also implement `Display` and provide the functionality that `OutlinePrint` needs.
We can do this in the trait definition by specifying `OutlinePrint: Display`.
This technique is similar to adding a trait bound to the trait.
Here shows an implementation of the `OutlinePrint` trait
```rust
use std::fmt;
trait OutlinePrint: fmt::Display {
fn outline_print(&self) {
let output = self.to_string();
let len = output.len();
println!("{}", "*".repeat(len + 4));
println!("*{}*", " ".repeat(len + 2));
println!("* {output} *");
println!("*{}*", " ".repeat(len + 2));
println!("{}", "*".repeat(len + 4));
}
}
```
Because we specified that `OutlinePrint` requires the `Display` trait.
We can use the `to_string` function that is automatically implemented for any type that implements `Display`.
If we attempted to use `to_string` without adding a color and specifying the `Display` trait after the trait name, we would get an error saying that no method named `to_string` was found for the type `&Self` in the current scope.
Lets see what happens when we try to implement `OutlinePrint` on a type that doesn't implement `Display`, such as the `Point` struct
```rust
struct Point {
x: i32,
y: i32,
}
impl OutlinePrint for Point {}
```
We still get an error saying that `Display` is required but not implemented
```
$ cargo run
Compiling traits-example v0.1.0 (file:///projects/traits-example)
error[E0277]: `Point` doesn't implement `std::fmt::Display`
--> src/main.rs:20:23
|
20 | impl OutlinePrint for Point {}
| ^^^^^ `Point` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `Point`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
note: required by a bound in `OutlinePrint`
--> src/main.rs:3:21
|
3 | trait OutlinePrint: fmt::Display {
| ^^^^^^^^^^^^ required by this bound in `OutlinePrint`
error[E0277]: `Point` doesn't implement `std::fmt::Display`
--> src/main.rs:24:7
|
24 | p.outline_print();
| ^^^^^^^^^^^^^ `Point` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `Point`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
note: required by a bound in `OutlinePrint::outline_print`
--> src/main.rs:3:21
|
3 | trait OutlinePrint: fmt::Display {
| ^^^^^^^^^^^^ required by this bound in `OutlinePrint::outline_print`
4 | fn outline_print(&self) {
| ------------- required by a bound in this associated function
For more information about this error, try `rustc --explain E0277`.
error: could not compile `traits-example` (bin "traits-example") due to 2 previous errors
```
In order to fix this, we implement `Display` on `Point` and satisfy the constraint that `OutlinePrint` requires.
Like this
```rust
use std::fmt;
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
```
Now implementing the `OutlinePrint` trait on `Point` will compile successfully.
We can call `outline_print` on a `Point` instance to display it within an outline of asterisks.
## Using the Newtype Pattern to Implement Traits on External Types
Previously we mentioned the orphan rule that states we are only allowed to implement a trait on a type if either the trait or the type are local to our crate.
It is possible to get around this restriction using the *newtype pattern*.
This involves creating a new type in a tuple struct.
The tuple struct will have one field and be a thin wrapper around the type we want to implement a trait for.
Then the wrapper type is local to our crate, and we can implement the trait on the wrapper.
*Newtype* is a term that originates from the Haskell programming language.
There is no runtime performance penalty for using this pattern, and wrapper type is elided at compile time.
For example let's say we want to implement `Display` on `Vec<T>`, which the orphan rule prevents us from doing directly because the `Display` trait and the `Vec<T>` type are defined outside our crate.
We can make a `Wrapper` struct that holds an instance of `Vec<T>`.
Next we can implement `Display` on `Wrapper` and use the `Vec<T>` value.
```rust
use std::fmt;
struct Wrapper(Vec<String>);
impl fmt::Display for Wrapper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}]", self.0.join(", "))
}
}
fn main() {
let w = Wrapper(vec![String::from("hello"), String::from("world")]);
println!("w = {w}");
}
```
The implementation of `Display` uses `self.0` to access the inner `Vec<T>`.
Because `Wrapper` is a tuple is a tuple struct and `Vec<T>` is the item at index 0 in the tuple.
Then we can use the functionality of the `Display` trait on `Wrapper`.
The downside of this technique is that `Wrapper` is a new type, so it doesn't have the methods of the value it is holding.
We would need to implement all the methods of `Vec<T>` directly on `Wrapper` such that the methods delegate to `self.0`, which would allows us to treat `Wrapper` exactly like a `Vec<T>`.
If we wanted the new type to have every method the inner type has, implementing the `Deref` trait on the `Wrapper` to return the inner type would be a solution.
If we didn't want the `Wrapper` type to have all the methods of the inner type.
For example, to restrict the `Wrapper` type's behavior we would have to implement just the methods we do want manually.
This newtype pattern is useful even when traits are not involved.

333
Advanced Types.md Normal file
View File

@ -0,0 +1,333 @@
# Advanced Types
The Rust type system has some features that we have mentioned so far but haven't gone into detail.
To start we will go into the newtypes in general as we examine why newtypes are useful as types.
Then we will go onto type aliases, a feature similar to newtypes but slightly different semantics.
As well we will discuss the `!` and dynamically sized types.
## Using the Newtype Pattern for Type Safety and Abstraction
The newtype pattern are also useful for tasks beyond those discussed already.
This includes statically enforcing that values are never confused and indicating the units of a value.
Before we saw an example of using newtypes to indicate units: recall that the `Millimeters` and `Meters` structs wrapped `u32` values in a newtype.
If we wrote a function with a parameter of type `Millimeters`, we couldn't compile a program that accidentally tired to call function with a value of type `Meters` or a plain `u32`.
We can also use the newtype pattern to abstract away some implementation details of a type.
The new type can expose a public API that is different form the API of the private inner type.
Newtypes can also hide internal implementation.
Lets say we could provide a `People` type to wrap a `HashMap<i32, String>` that store a person's ID associated with their name.
Code using `People` would only interact with the public API we provide.
Like a method to add a name string to the `People` collect: this code wouldn't need to know that we assign an `i32` ID to names internally.
The newtype pattern is a lightweight way to achieve encapsulation to hide implementation details, which we discussed before in [Ch18](./Characteristics%20of%20OO%20Languages.md#encapsulation-that-hides-implementation-details).
## Creating Type Synonyms with Type Aliases
Rust provides the ability to declare a *type alias* to give an existing type another name.
We need to use the `type` keyword to do this.
For example we can create the alias `Kilometers` to `i32` like this.
```rust
type Kilometers = i32;
```
The alias `Kilometers` is a *synonym* for `i32`.
Unlike the `Millimeters` and `Meters` types we created before.
`Kilometers` is not a separate, new type.
Values that have the type `Kilometers` will be treated the same as values of type `i32`.
```rust
type Kilometers = i32;
let x: i32 = 5;
let y: Kilometers = 5;
println!("x + y = {}", x + y);
```
Because `Kilometers` and `i32` are the same type, we can add values of both types and we can pass `Kilometers` values to functions that take `i32` parameters.
However using this method, we don't get the type checking benefits that we get from the newtype pattern discussed earlier.
In other words, if we mix up `Kilometers` and `i32` values somewhere, the compiler will not give us an error.
The main use for type synonyms is to reduce repetition.
As an example, we might have a lengthy type like this.
```rust
Box<dyn Fn() + Send + 'static>
```
Writing this lengthy type function signatures and as type annotations all over the code can be tiresome and error prone.
Just image a project full of code like this.
```rust
let f: Box<dyn Fn() + Send + 'static> = Box::new(|| println!("hi"));
fn takes_long_type(f: Box<dyn Fn() + Send + 'static>) {
// --snip--
}
fn returns_long_type() -> Box<dyn Fn() + Send + 'static> {
// --snip--
}
```
A type alias makes this code more manageable by reducing the amount of repetition.
Here we have introduced an alias named `Thunk` for the verbose type and can replace all uses of the type with the shorter alias `Thunk`.
```rust
type Thunk = Box<dyn Fn() + Send + 'static>;
let f: Thunk = Box::new(|| println!("hi"));
fn takes_long_type(f: Thunk) {
// --snip--
}
fn returns_long_type() -> Thunk {
// --snip--
}
```
This is much easier to read and write.
Choosing a meaningful name for a type alias can help communicate your intent as well.
*Thunk* is a word for code to be evaluated at a later time, this is an appropriate name for a closure that gets stored.
Type aliases are also commonly used with the `Result<T, E>` type for repetition.
Consider the `std::io` module in the std library.
I/O operations often return a `Result<T, E>` to handle situations when operations fail to work.
This library has a `std::io::Error` struct that represents all possible I/O errors.
Many of the functions in `std::io` will be returning `Result<T, E>` where the `E` is `std::io::Error`, such as these functions in `Write` trait:
```rust
use std::fmt;
use std::io::Error;
pub trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize, Error>;
fn flush(&mut self) -> Result<(), Error>;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Error>;
fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Error>;
}
```
The `Result<..., Error>` is repeated a lot.
Therefore `std::io` has this type alias declaration
```rust
type Result<T> = std::result::Result<T, std::io::Error>;
```
Due to this declaration is in the `std::io` module, we can use the fully qualified alias `std::io::Result<T>`.
That is a `Result<T, E>` with the `E` filled in as `std::io::Error`.
The `Write` trait function signatures end up looking like this.
```rust
pub trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize>;
fn flush(&mut self) -> Result<()>;
fn write_all(&mut self, buf: &[u8]) -> Result<()>;
fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()>;
}
```
This type alias helps in two ways:
- It makes code easier to write.
- *And*
- It gives us a consistent interface across all of `std::io`
Due to it being an alias, it is just another `Result<T, E>`, this means we can use any methods that work on `Result<T, E>` with it, as well as special syntax like the `?` operator.
## The Never Type that Never Returns
Rust has a special type named `!` that is known in type theory lingo as the *empty type* because it has no values.
We prefer to call it the *never type* because it stands in the place of the return type when a function will never return.
Here is an example in use.
```rust
fn bar() -> ! {
// --snip--
}
```
This code should be read as "the function `bar` returns never."
Functions that return never are called *diverging functions*.
We can't create values of the type `!` so `bar` can never possibly return.
What is the use of a type you can never create values for?
Recall the code from Ch2, part of the number guessing game.
Here is a sample of that code
```rust
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
```
Before we skipped over some details about this code.
In ch6 we discussed that `match` arms must all return the same type.
For example this code will not compile.
```rust
let guess = match guess.trim().parse() {
Ok(_) => 5,
Err(_) => "hello",
};
```
The type of `guess` in this code would have to be an integer *and* a string, and Rust requires that `guess` have only one type.
So what does `continue` return?
How are we allowed to return a `u32` from one arm and have another arm that ends with `continue`?
`continue` has a `!` value.
That is, when Rust computes the type of `guess`, it looks at both match arms, the former with a value of `u32` and the latter with a `!` value.
Because `!` can never have a value, Rust decides that the type of `guess` is `u32`.
The formal way to describe this behavior is that expressions of type `!` can be coerced into any other type.
We are allowed to end this `match` arm with `continue` because `continue` doesn't return a value.
Instead it moves control back to the top of the loop, so in the `Err` case, we never assign a value to `guess`.
The never type is useful with the `panic!` macro as well.
Remember the `unwrap` function that we call on `Option<T>` values to produce a value or panic with this definition:
```rust
impl<T> Option<T> {
pub fn unwrap(self) -> T {
match self {
Some(val) => val,
None => panic!("called `Option::unwrap()` on a `None` value"),
}
}
}
```
Here, the same thing happens as in the `match` case form before.
Rust sees that `val` has the type `T` and `panic!` has the type `!`, so the result of the overall `match` expression is `T`.
This works because `panic!` doesn't produce a value, it ends the program.
In the `None` case, we will not be returning a value form `unwarp` so this code is valid.
One final expression that has the type `!` is a `loop`.
```rust
print!("forever ");
loop {
print!("and ever ");
}
```
This loop never ends, so `!` is the value of the expression.
However, this wouldn't be true if we included a `break`, because the loop would terminate when it got to the `break`.
## Dynamically Sized Types and the `Sized` Trait
Rust must know certain details about its types, such as how much space to allocate for a value of a particular type.
This leaves one corner of its type system a little confusing at first: the concept of *dynamically sized types*.
Sometimes referred to as *DSTs* or *unsized types*, these types let us write code using values whose size we can know only at runtime.
Lets look into the details of a dynamically sized type called `str`, which we have been using throughout.
This does not include `&str`, but `str` on its own, is a DST.
We can't know how long the string is until runtime, meaning we can't create a variable of type `str`, nor can we make that argument of type `str`.
Consider this code, which will not compile.
```rust
let s1: str = "Hello there!";
let s2: str = "How's it going?";
```
Rust needs to know how much memory to allocate for any value of a particular type, and all values of a type must use the same amount of memory.
If Rust allowed use to write this code, these two `str` values would need to take up the same amount of memory.
These two have different lengths:
- `s1` needs 12 bytes of storage.
- `s2` needs 15.
This is why it is not possible to create a variable holding a dynamically sized type.
So what should we do?
We should make the types of `s1` and `s2` a `&str` rather than a `str`.
Recall from the "String Slice" section from Ch4, that the slice data structure just stores the starting position and the length of the slice.
Even though a `&T` is a single value that stores the memory address of where the `T` is located, a `&str` is *two* values.
The address of the `str` and its length.
We can know the size of a `&str` value at compile time: it's twice the length of a `usize`.
This means we always know the size of a `&str`, no matter how long the string it refers to is.
Generally this is the way in which dynamically sized types are used in Rust, they have an extra but of metadata that stores the size of the dynamic information.
The golden rule of dynamically sized types is that we must always put values of dynamically sized types behind a pointer of some kind.
We can combine `str` with all kinds of pointers.
For example `Box<str>` or `Rc<str>`.
In fact we have seen this before but with a different dynamically sized type: traits.
Every trait is a dynamically sized type we can refer to by using the name of the trait.
In Ch18 in ["Using Trait Objects That Allow for Values of Different Types"](./Characteristics%20of%20OO%20Languages.md#encapsulation-that-hides-implementation-details), we mentioned that to use trait as trait objects, we must put them behind a pointer, such as `&dyn Trait` or `Box<dyn Trait>` (`Rc<dyn Trait>` would work as well).
To work with DSTs, Rust provides the `Sized` trait to determine whether or not a type's size is known at compile time.
This trait is automatically implemented for everything whose size is known at compile time.
Additionally Rust implicitly adds a bound on `Sized` to every generic function.
That is, a generic function definition like this:
```rust
fn generic<T>(t: T) {
// --snip--
}
```
This is actually treated as though we had written this:
```rust
fn generic<T: Sized>(t: T) {
// --snip--
}
```
By default, generic functions will work only on types that have a known size at compile time.
However, you can use the following special syntax to relax this restriction.
```rust
fn generic<T: ?Sized>(t: &T) {
// --snip--
}
```
A trait bound on `?Sized` means "`T` may or may not be `Sized`".
This notation overrides the default that generic types must have a known size at compile time.
The `?Trait` syntax with this meaning is only available for `Sized`, not any other traits.
Note that we switched the type of the `t` parameter from `T` to `&T`.
Because the type might not be `Sized`, we need to use it behind some kind of pointer.
Here we have chosen to use a reference.

View File

@ -0,0 +1,177 @@
# Characteristics of Object-Oriented Languages
There is no consensus about what features a language must have to be considered object-oriented.
Rust is influenced by many programming paradigms, including OOP.
Arguably, OOP languages share certain common characteristics, namely objects, encapsulations and ingeritance.
Lets see what each of those means and whether Rust supports it.
## Object Contain Data and Behavior
The book _Design Patterns: Elements of Reusable Object-Oriented Software_ by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Addison-Wesley Professional, 1994).
This is colloquially referred to as _The Gang of Four_ book, is a catalog of object-oriented design patters.
It defines OOP as this:
Object-oriented programs are made up of objects.
An _object_ packages both data and the procedures that operate on that data.
The procedures are typically called _methods_ or _operations_.
Using this definition, Rust is object-oriented: structs and enumbs have data, and `impl` blocks provide methods on structs and enums.
Even though structs and enums with methods aren't _called_ obejcts, they provide the same functionaliy accound to the Gang of Four's definition of objects.
## Encapsulation that Hides Implementation Details
An aspect commonly associated with OOP is the idea of _encapsulation_.
This means that the implementation details of an object aren't accessible to code using that object.
Therefore, the only way to interact with an object is through its public API.
Code using the object shouldn't be able to reach into the object's internals and change data or behaviro directly.
This enables the programmer to change and refactor an object's internals without needing to change the code that uses the object.
We discussed previously how to control encapsulation in Ch7.
We can use the `pub` keyword to decide which modules, types, function and methods in our code should be public .
By default everything else is private.
For example, if we defined a struct `AveragedCollection` that has a field containing a vector of `i32` values.
The struct can also have a field that contains the average of te vlaues in the vector, meaning the average doesn't have to be computed on demand whenever anyone needs it.
In other words, `AveragedCollection` will cache the calculated average of the values in the vector.
Meaning the average doesn't have to be computed on demand whenever it is needed.
`AveragedCollection` will cache the calculated average for us.
Here is the definition of the `AveragedCollection` struct
```rust
pub struct AveragedCollection {
list: Vec<i32>,
average: f64,
}
```
This struct is marked `pub` os that other code can use it.
The fields within the struct remain private.
This is improtant becuase we want to ensure that whenever a value is added or removed from the lust, the average is also updated.
We accomplish this by implementing `add`, `remove` and `average` methods on the struct.
This is shown here
```rust
impl AveragedCollection {
pub fn add(&mut self, value: i32) {
self.list.push(value);
self.update_average();
}
pub fn remove(&mut self) -> Option<i32> {
let result = self.list.pop();
match result {
Some(value) => {
self.update_average();
Some(value)
}
None => None,
}
}
pub fn average(&self) -> f64 {
self.average
}
fn update_average(&mut self) {
let total: i32 = self.list.iter().sum();
self.average = total as f64 / self.list.len() as f64;
}
}
```
The public methods, `add`, `remove` and `average` are the only ways to access or modify data in any instance of `AverageCollection`.
When an item is added or removed to `list`, using the associated method, the implementations of each call the private `update_average` method that handles updating the `average` field as well.
We leave the `list` and `average` fields private, so that there is no way for external code to add or remove items to or form the `list` field directly.
The `average` method returns the value in the `average` field, this allows for external code to read the `average` but not modify it.
Because we have encapsulated the impleentation details of `AveragedCollection`.
We can easily change aspects, such as the data structure, in the future.
For example, we could use a `HashSet<i32>` instead of a `Vec<i32>` for the `list` field.
As long as the signatures of the `add`, `remove`, and `average` public methods stay the same.
Code using `AveragedCollection` wouldn't need to change to order to compile.
If we made `list` public instead, this wouldn't necessarily be the case
`HashSet<i32>` and `Vec<i32>` have different methods for adding and removing items, so the external code would likely have to change if it were modifying `list` directly.
If encapsulation is a required aspect for a language to be considered object-oriented, then Rust meets that requirement.
The option to use `pub` or not for different parts of code enbalbes encapsulation of implementation details
## Inheritance as a type System and as Code Sharing
_Inheritance_ is a mechanism whereby an object can inherit elements from another obejct's definition, thus gaining the parent object's data and behavior without you having to define them again.
If a language must have inheritance to be an obejct-oriented, then Rust is not one.
There is no way to define a struct that inherits the parent struct fields and method implementations without using a macro.
However, if you are use to having this tool available, you cna use other solutions in Rust, depending on your reason for reaching for inheritance.
Yuo choose inheritance for main reasons.
Resue of code: you can implement particular behavior for one type, and ingeritance enables ou to reuse that implementation for a different type.
You can do this in a limited way in Rust ocde using default trait method implementations.
We saw this before with the default implemetnation of the `summarize` method on the `Summary` trait.
Any type implementing the `Summary` trait would have the `summarize` method available on it without any further code.
This is similar to a parent class having an implementation of the `summarize` method when we `implement` the `Summary` trait, which is similar to a child class overriding the implementation of a method inherited form a parent class.
The other resaon to use ingeritance relates to the type system: to enable a child to be used in the same place as the parent type.
This has another name _polymorphism_, which means that you can substitute multiple objects for each other at runtime if they share certain characteristics.
### Polymorphism
To many this is synonymous with inheritance.
But it is actually a more general concept that refers to code that can work with data of multiple tpyes.
For inheritance, those types are generally subclasses.
Rust instead use generics to abstract over different possible types and trait bounds to impose constraints on what those tpyes must provide.
This is sometimes called *bounded parametric polymorphism*.
Inheritance has recently fallen out of favor as a programming deisgn solution, becuase it is often at risk of sharing more code than necessary.
Subclasses shouldn't always share all characteristics of thier parent class but will do so with inheritance.
This can make a program's design less flexible.
This also introduces the possibility of calling methods on subclasses that don't make sense or that cause errors because the methods don't apply to the subclass.
Additionally some languages will only allow single inheritance, meaning a subclass can only inherit from one class, thus further restricting the flexibility of a program's design.
These reasons are why Rust takes the different approach of using trait objects instead of inheritance.
Next lets see how trait obejcts enable polymorphism in Rust. [Here](./Trait%20Objects%20that%20allow%20for%20Values%20of%20Different%20Types.md)

View File

@ -0,0 +1,157 @@
# Putting It All Together: Futures, Tasks and Threads
As we saw [here](./Concurrency.md), threads provide one approach to concurrency.
Another approach was using async with futures and streams.
If you were wondering when to choose one over the other.
The answer is that it depends, and in many cases, the choice isn't threads *or* async but rather threads *and* async.
Many OS have supplied threading-based concurrency models for decades now, and many programming results support them as a result.
These models are not without their own tradeoffs.
On many OSes, they use a fair bit of memory, and they come with some overhead for starting up and shutting down.
Threads are also only an option when your OS and hardware support them.
Unlike a modern desktop and mobile computer, some embedded systems don't have an OS at all, so they also don't have threads.
The async model provides a different and complementary set of tradeoffs.
In the async model, concurrent operations don't require their own threads.
Instead, they can run on tasks (just like when we used `trpl::spawn_task`)m this kicks off work form a synchronous function in the streams section.
A task is similar to a thread, instead of being managed by the OS, it is managed by library-level code: the runtime
Previously, we saw that we could build a stream by using async channel and spawning an async task we could call from synchronous code.
We then can do this exact same thing with a thread.
Before we used `trpl::spawn_task` and `trpl::sleep`.
Here we replaced those with the `thread::spawn` and `thread::sleep` APIs from the std library in the `get_intervals` function.
```rust
fn get_intervals() -> impl Stream<Item = u32> {
let (tx, rx) = trpl::channel();
// This is *not* `trpl::spawn` but `std::thread::spawn`!
thread::spawn(move || {
let mut count = 0;
loop {
// Likewise, this is *not* `trpl::sleep` but `std::thread::sleep`!
thread::sleep(Duration::from_millis(1));
count += 1;
if let Err(send_error) = tx.send(count) {
eprintln!("Could not send interval {count}: {send_error}");
break;
};
}
});
ReceiverStream::new(rx)
}
```
If you run this code it will produce an identical output as the one before.
And notice how little changes here from the perspective of calling code.
What is more even though one of our functions spawned an async task on the runtime and the other spawned an OS thread.
The resulting streams were unaffected by the differences.
Despite their similarities, these two behave very differently, although we might have a hard time measuring it in this very simple example.
Alternatively we could spawn millions of async tasks on any modern personal computer.
If we tried to do that with threads, we would literally run out of memory.
There is a reason that these APIs are so similar.
Threads act as a boundary for sets of synchronous operations; concurrency is possible *between* threads.
Tasks act as a boundary for sets of *asynchronous* operations.
Concurrency is possible both *between* and *within* tasks, because a task can switch between futures in its body.
Finally, futures are Rust's most granular unit of concurrency, and each future may represent a tree of other futures.
The runtime (specifically, its executor) manages tasks and tasks manage futures.
In this regard, tasks are similar to lightweight, runtime-managed threads with added capabilities that come from being managed by a runtime instead of by the operating system.
This doesn't mean that async tasks are always better than threads (or vice versa).
Concurrency with threads is in some ways a simpler programming model than concurrency with `async`.
This can be either a strength or a weakness.
Threads are somewhat "fire and forget".
They have no native equivalent to a future, so they simply run to completion without being interrupted except by the OS itself.
That is they have no built-in support for *intratask concurrency* the way futures do.
Threads in Rust also have no mechanisms for cancellation (we haven't covered explicitly in this ch but was implied by the fact that whenever we ended a future, tis state got cleaned up correctly).
The limitations also make threads harder to compose than futures.
This is much more difficult.
For example, to use threads to build helpers such as the `timeout` and `throttle` methods that we built earlier.
The fact that futures are richer data structures means they can be composed together more naturally as we have seen.
Tasks, give us *additional* control over futures, allowing us to choose where and how to group them.
It turns out that threads and tasks often work very well together, because tasks (in some runtimes) can be moved around between threads.
In fact, under the hood, the runtime we have been using including the `spawn_blocking` and `spawn_task` functions is multithreaded by default.
Many runtimes use an approach called *work stealing* to transparently move tasks around between threads.
Based on how the threads are currently being utilized, to improve the system's overall performance.
This approach actually requires threads *and* tasks and therefore futures.
When thinking about which method to use when, consider these rules of thumb:
- If the work is *very parallelizable*, such as processing a bunch of data where each part cab be processed separately, threads are a better choice.
- If the work is *very concurrent*, such as handling message from a bunch of different sources that many come in at different intervals or different rates, async is a better choice.
If you need both concurrency and parallelism, you don't have to choose between threads and async.
You can use them together freely, letting each one play the part it is best at.
An example of this, below, shows a fairly common example of this kind of mix in real-world Rust code.
```rust
use std::{thread, time::Duration};
fn main() {
let (tx, mut rx) = trpl::channel();
thread::spawn(move || {
for i in 1..11 {
tx.send(i).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
trpl::run(async {
while let Some(message) = rx.recv().await {
println!("{message}");
}
});
}
```
Here we being by creating an async channel, then spawn a thread that takes ownership of the sender side of the channel.
Within the thread, we send the numbers 1-10, sleeping for a second between each.
Finally, we run a future created with an async block passed to `trpl::run` just as we have throughout the chapter.
In this future, we await those messages, just as in the other message-passing examples we have seen.
Returning to the scenario we opened the chapter with, imagine running a set of video encoding tasks using a dedicated thread (because video encoding is compute-bound) but notifying the UI that those operations are dont with an async channel.
There are countless examples of these kinds of combinations in real-world use cases.

View File

@ -0,0 +1,704 @@
# Implementing an Object-Oriented Design Pattern
The *state pattern* is an object-oriented design pattern.
The crux of the pattern is that we define a set of states a value can have internally.
The states are represented by a set of *state objects* and the value's behavior changes based on its state.
We are going to work through an example of a blog post struct that has aa filed to hold its state, this will be a state object form the set "draft", "review", or "published".
The sate objects share functionality. In Rust we use structs and traits rather than objects and inheritance.
Each state object is responsible for its own behavior and for governing when it should change into another state.
The value that holds a state object knows nothing about the different behavior of the states or when to transition between states.
The advantage of using this is that when the business requirements of the program change, we won't need to change the code of the value holding the state or the code that uses the value.
We will only need to update the code inside one of the state objects to change its rules or perhaps add more state objects.
We are going to implement the state pattern in a more tradition object-oriented way.
Next we will use an approach that is a bit more natural in Rust.
Lets start with incrementally implementing a blog post workflow using the state pattern.
The final functionality will look like this:
1. A blog post starts as an empty draft
2. When the draft is complete, a review of the post is requested
3. When the post is approved, it will be published
4. Only published blog posts return content to print, so unapproved posts can't be accidentally be published
Any other changes attempted on a post should have no effect.
An example of this is if we try to approve a draft blog post before we have requested a review, the post should remain an unpublished draft.
In this example, it shows the workflow in code form.
This is an example usage of the API, we will implement in a library crate named `blog`.
This will not compile yet because we haven't implemented the `blog` crate.
```rust
use blog::Post;
fn main() {
let mut post = Post::new();
post.add_text("I ate a salad for lunch today");
assert_eq!("", post.content());
post.request_review();
assert_eq!("", post.content());
post.approve();
assert_eq!("I ate a salad for lunch today", post.content());
}
```
We want to allow the user to create a new draft blog post with `Post::new`.
We also want to allow text to be added to be blog post.
If we try to get the post's content immediately, before approval, we shouldn't get any text because the post is still a draft.
We added `assert_eq!` for demonstration purposes.
An excellent unit test for this would be to assert that a draft post returns an empty string from the `content` method, but we are not going to write tests for this example.
Next, we want to enable a request for a review of the post and we want `content` to return an empty string while waiting for the review.
Then when the post receives approval, it should get published, meaning the text of the post will be returned when `content` is called.
Note that the only type we are interacting with from the crate s the Post type.
This type will use the state pattern and will hold a value that will be one of three state objects representing the various states a post can be in, draft, waiting for review or published.
Changing from one state change in response to the methods called by our library users on the `Post` instance.
They don't have to manage the state changes directly.
Users can't make a mistake with the states, like publishing a post before it is reviewed.
## Defining `Post` and Creating a New Instance in the Draft State
First we need a public `Post` struct that holds some content.
so we will start with the definition of the struct and the associated public `new` function to create an instance of `Post`.
This is shown below.
We will also make a private `State` trait that will define the behavior that all state objects for a `Post` must have.
`Post` will hold a trait object of `Box<dyn State>` inside an `Option<T>` in a private field named `state` to hold the state object.
You will see why the `Option<T>` is necessary.
```rust
pub struct Post {
state: Option<Box<dyn State>>,
content: String,
}
impl Post {
pub fn new() -> Post {
Post {
state: Some(Box::new(Draft {})),
content: String::new(),
}
}
}
trait State {}
struct Draft {}
impl State for Draft {}
```
The `State` trait defines the behavior shared by different post states.
The state objects are `Draft`, `PendingReview` and `Published`, and they will all implement the `State` trait.
For now the trait doesn't have any methods.
We will start by defining just the `Draft` state because that is the state we want a post to start in.
When we create a new `Post`, we set its `state` field to a `Some` value that holds a `Box`.
This `Box` points to aa new instance of the `Draft` struct.
This ensures whenever we create a new instance of `Post`, it will start out as a draft.
Due to the state field of `Post` being private, there is no way to create a `Psot` in any other state.
In the `Post::new` function, we set the `content` field to a new empty `String`.
## Storing the Text of the Post Content
Previously we saw that we wanted to be able to call a method named `add_test` and pass it a `&str` that is then added as the text content of the blog post.
We implemented this as a method, rather than exposing the `content` field as `pub`, so that later we can implement a method that will control how the `content` field's data is read.
The `add_text` method is fairly straightforward, so lets add the implementation below to the `impl Post` block.
```rust
impl Post {
// --snip--
pub fn add_text(&mut self, text: &str) {
self.content.push_str(text);
}
}
```
The `add_text` method takes a mutable reference to `self`.
Because we changed the `Post` instance that we are calling `add_text` on.
We then can call `push_str` on the `String` in `content` and pass the `text` argument to add to the saved `content`.
This behavior doesn't depend on the state the post is in, so it is not part of the state pattern.
The `add_text` method doesn't interact with the `state` field at all, but it is part of the behavior we want to support.
## Ensuring the Content of a Draft Post Is Empty
Even after we called `add_text` and added some content to our post, we still want the `content` method to return an empty string slice because the post is still in the draft state.
For now we will implement the `content` method with the simplest thing that will fulfill this requirement.
Always returning an empty string slice.
We will change this late once we implement the ability to change a post's state so that it can be published.
Posts so far can only be in the draft state., so the post content should always be empty.
Here is a placeholder implementation:
```rust
impl Post {
// --snip--
pub fn content(&self) -> &str {
""
}
}
```
## Requesting a Review of the Post Changes Its State
Next we need to add functionality to request a review of a post, which should change its state from `Draft` to `PendingReview`
Here is the code that shows this
```rust
impl Post {
// --snip--
pub fn request_review(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.request_review())
}
}
}
trait State {
fn request_review(self: Box<Self>) -> Box<dyn State>;
}
struct Draft {}
impl State for Draft {
fn request_review(self: Box<Self>) -> Box<dyn State> {
Box::new(PendingReview {})
}
}
struct PendingReview {}
impl State for PendingReview {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
}
```
Here `request_review` is a public method on the `Post` struct, this will take a mutable reference to `self`.
Then we call an internal `request_review` method on the current state of `Post`.
The second `request_review` method consumes the current state and returns a new state.
We add the `request_review` method to the `State` trait.
Now all types that implement the trait will now need to implement the `request_review` method.
Note, rather than having `self`, `&self` or `&mut self` as the first parameter of the method, we have `self: Box<Self>`.
This syntax means the method is only valid when called on a `Box` holding the type.
This syntax takes ownership of `Box<Self>`, invalidating the old state so the state value of the `Post` can transform into a new state.
In order to consume the old state, the `request_review` method needs to take ownership of the state value.
This is where the `Option` in the `state` filed of `Post` comes in.
We call the `take` method to take the `Some` value out of the `state` field and leave a `None` in its place, because Rust not allowing us to have unpopulated fields in structs.
This lets us move the `state` value out of `Post` rather than borrowing it.
Then we will set the post's `state` value to the result of this operation.
We need to set `state` to `None` temporarily rather than setting it directly with something like `self.state = self.state.request_review();` to get ownership of the `state` value.
This ensures that `Post` can't use the old `state` value after we transformed it into a new state.
The `request_review` method on `Draft` returns a new boxed instance of a new `PendingReview` struct.
This represents the state when a post is waiting for a review.
The `PendingReview` struct also implements the `request_review` method but doesn't do any transformations.
It instead returns itself, because when we request a review on a post already in the `PendingReview` state, it should stay in the `PendingReview` state.
Now the advantages of the state pattern are staring to be seen: the `request_review` method on `Post` is the same no matter its `state` value.
Each state is responsible for its own rules.
We leave the `content` method on `Post` as is, returning an empty string slice.
We can now have a `Post` in the `PendingReview` state as well as in the `Draft` state, but we want the same behavior in the `PendingReview` state.
## Adding `approve` to Change the Behavior of `content`
The `approve` method will be similar to the `request_review` method.
It will set `state` to the value that the current state says it should have when that state is approved.
Here is the new code
```rust
impl Post {
// --snip--
pub fn approve(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.approve())
}
}
}
trait State {
fn request_review(self: Box<Self>) -> Box<dyn State>;
fn approve(self: Box<Self>) -> Box<dyn State>;
}
struct Draft {}
impl State for Draft {
// --snip--
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
}
struct PendingReview {}
impl State for PendingReview {
// --snip--
fn approve(self: Box<Self>) -> Box<dyn State> {
Box::new(Published {})
}
}
struct Published {}
impl State for Published {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
}
```
Here we added the `spprove` method to the `State` trait and add a new struct that implements `State`, the `Published` state.
Similar to how `request_review` on `PendingReview` works, if we call the `approve` method on a `Draft`, it will have no effect because `approve` will return `self`.
When we call `approve` on `PendingReview`, it returns a new boxed instance of the `Published` struct.
The `Published` struct implements the `State` trait, and for both the `request_review` method and the `approve` method, it returns itself, because the post should stay in the `Published` state in those cases.
We now need a way to update the `content` method on `Post`.
We want the value returned from `content` to depend on the current state of `Post`, so we are going to have the `Post` delegate to `cotnent` method defined on its `state`.
Here is the code for this
```rust
impl Post {
// --snip--
pub fn content(&self) -> &str {
self.state.as_ref().unwrap().content(self)
}
// --snip--
}
```
The goal is to keep all the rules inside the structs that implement `State`.
We call a `content` method on the value in `state` and pass the post instance (that is `self`) as an argument.
Then we return the value that is returned from using the `content` method on the `state` value.
As we call the `as_ref` method on the `Option` because we want a reference to the value inside the `Option` rather than ownership of the value.
Because `state` is an `Option<Box<dyn State>>`, when we call `as_ref`, an `Option<&Box<dyn State>>` is returned.
If we didn't call `as_ref`, we would get an error because we can't move `state` out of the borrowed `&self` of the function parameter.
Then we call the `unwrap` method, we know this will never panic.
We know the methods on `Post` ensure that `state` will always contain a `Some` value when those methods are done.
This is a case where we have more information than the compiler (previously discussed in [Ch 9](./Error%20Handling.md#cases-in-which-you-have-more-info-than-the-compiler)) when we know that a `None` value is never possible, even though the compiler isn't able to understand that.
Now at this point, when we call `content` on the `&Box<dyn State>`, deref coercion will take effect on the `&` and the `Box` so the `content` method will ultimately be called on the type that implements the `State` trait.
This means we need to add `content` to the `State` trait definition, and that is where we will put the logic for what content to return depending on which state we have.
Here is that addition
```rust
trait State {
// --snip--
fn content<'a>(&self, post: &'a Post) -> &'a str {
""
}
}
// --snip--
struct Published {}
impl State for Published {
// --snip--
fn content<'a>(&self, post: &'a Post) -> &'a str {
&post.content
}
}
```
Here we added a default implementation for the `content` method that returns an empty string slice.
This means we don't need to implement `cotent` on the `Draft` and `PendingReview` structs.
The `Published` struct will override the `content` method and return the value in `post.content`.
Note that we need a lifetime annotation on this method.
Here we are taking a reference to a `post` as an argument and returning a reference to part of that `post`, so the lifetime of the returned reference is related to the lifetime of the `post` argument.
We have finally implemented the state pattern with the rules of the blog post workflow.
The logic related to the rules lives in the state objects rather than being scattered throughout `Post`.
Final Code:
```rust
pub struct Post {
state: Option<Box<dyn State>>,
content: String,
}
impl Post {
pub fn new() -> Post {
Post {
state: Some(Box::new(Draft {})),
content: String::new(),
}
}
pub fn add_text(&mut self, text: &str) {
self.content.push_str(text);
}
pub fn content(&self) -> &str {
self.state.as_ref().unwrap().content(self)
}
pub fn request_review(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.request_review())
}
}
pub fn approve(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.approve())
}
}
}
trait State {
// --snip--
fn request_review(self: Box<Self>) -> Box<dyn State>;
fn approve(self: Box<Self>) -> Box<dyn State>;
fn content<'a>(&self, post: &'a Post) -> &'a str {
""
}
}
// --snip--
struct Draft {}
impl State for Draft {
fn request_review(self: Box<Self>) -> Box<dyn State> {
Box::new(PendingReview {})
}
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
}
struct PendingReview {}
impl State for PendingReview {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
fn approve(self: Box<Self>) -> Box<dyn State> {
Box::new(Published {})
}
}
struct Published {}
impl State for Published {
// --snip--
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
fn content<'a>(&self, post: &'a Post) -> &'a str {
&post.content
}
}
```
### Why Not An Enum?
You may wonder why we didn't use an `enum` with the different possible post states as variants.
This is a possible solution, you have to try it and compare the end results to see which is preferred.
One disadvantage of using an enum is every place that checks the value of the enum will need a `match` expression or similar to handle every possible variant.
This could get more repetitive than this trait object solution.
## Trade-offs of the State Pattern
Here we have shown that Rust is capable of implementing the object-oriented state pattern to encapsulate the different kinds of behavior a post should have in each state.
The methods on `Post` know nothing about the various behaviors.
The way in which code is organized, we have to look only in one place to know the different ways a published post can behave: the implementation of the `State` trait on the `Published` struct.
If we were to create an alternative implementation that didn't use the state pattern, we might instead use `match` expression in the `Post` or even in the `main` code.
This would check for the state of the post and changes behavior ion those places.
That means we would have to look in several places to understand all the implications of a post being in the published state.
This would only increase the more states we added: each of those `match` expressions would need another arm.
With the state pattern, the `Post` methods and the places we use `Post` don't need `match` expressions and to add a new state.
We would only need to add a new struct and implement the trait methods on that one struct.
The implementation using the state pattern is easy to extend to add more functionality.
To highlight the simplicity of maintaining code that uses the state pattern, try a few of these suggestions:
- Add a `reject` method that changes the post's state from `PendingReview` back to `Draft`.
- Require two calls to approve before the state can be changed to `Published`.
- Allow users to add text content only when a post is in the `Draft` state.
- Hint: have the state object responsible for what might change about the content but not responsible for modifying the `Post`.
One downside of the state pattern is that, because the states implement the transitions between states, some of the states are coupled to each other.
If we add another state between `PendingReview` and `Published`, such as `Scheduled`, we would have to change the code in `PendingReview` to transitioned to `Scheduled` instead.
It would be less work if `PendingReview` didn't need to change with the addition of a new state, but that would mean switching to another design pattern.
Another downside is that we have dupliced some logic.
In order to eliminate some of the duplication, we may try to make default implementations for the `request_review` and `approve` methods on the `State` trait that return `self`
However, this would not be dyn compatible.
This is because the trait doesn't know what the concrete `self` will be exactly.
We want to be able to use `State` as a trait object so we need its methods to be dyn compatible.
Other duplication includes the similar implementations of the `request_review` and `approve` methods on `Post`.
Both methods delegate to the implementation of the same method on the value in the `state` field of `Option` and set the new value of the `state` field to the result.
If we had a lot of methods on `Post` that followed this pattern, we may consider defining a macro to eliminate the repetition (This will be discussed in Ch20).
By implementing the state pattern exactly as it is defined for object-oriented languages, we are not taking full advantage of Rust's strengths as we could.
Now lets look at some changes to make the `blog` crate that can make invalid states and transitions into compile time errors.
## Encoding States and Behavior as Types
We will show how you can rethink the state pattern to get a different set of trade-offs.
Rather than encapsulating the states and transitions completely so outside code has no knowledge of them, we will encode the states into different types.
Rust's type checking system will prevent attempts to use draft posts where only published posts are allowed by issuing a compiler error.
Lets consider this first part of `main` from before
```rust
fn main() {
let mut post = Post::new();
post.add_text("I ate a salad for lunch today");
assert_eq!("", post.content());
}
```
We still need to enable the creation of new posts in the draft state using `Post::new` and the ability to add text to the post's content.
Instead of having a `content` method on a draft post that returns an empty string, we will make it so draft posts don't have the `content` method at all.
This way if we try to get a draft post's content, we will get a compiler error telling us the method doesn't exist.
This results in being impossible for us to accidentally display draft post content in production, because that code won't even compile.
Here is the definition of a `Post` struct and a `DraftPost` struct as well as methods on each.
```rust
pub struct Post {
content: String,
}
pub struct DraftPost {
content: String,
}
impl Post {
pub fn new() -> DraftPost {
DraftPost {
content: String::new(),
}
}
pub fn content(&self) -> &str {
&self.content
}
}
impl DraftPost {
pub fn add_text(&mut self, text: &str) {
self.content.push_str(text);
}
}
```
Both the `Post` and `DraftPost` structs have a private `content` field that stores the blog post text.
The structs no longer have the `state` field because we are moving the encoding of that state to the types of structs.
The `Post` struct will represent a published post, and it has a `content` method that returns the `content`.
We still have a `Post::new` function, but instead of returning an instance of `Post`, it returns an instance of `DraftPost`.
Due to `content` being private and there aren't any functions that return `Post`, it is not possible to create an instance of `Post` right now.
The `DraftPost` struct has an `add_text`method, so we can add text to `content` as before.
Note that `DraftPost` does not have a `content` method defined.
So now the program ensures all posts start as draft posts, and draft posts don't have their content available for display.
Any attempt to get around these constraints will result in a compiler error.
## Implementing Transitions as Transformations into Different Types
How do we get a published post?
We want to enforce the rule that a draft post has to be reviewed and approved before it can be published.
A post in the pending review state should still not display any content.
We will implement these constraints by adding another struct, `PendingReviewPost`.
We will define the `request_review` method on `DraftPost` to return a `PendingReviewPost`.
Finally we will define an `approve` method on `PendingReviewPost` to return a `Post`.
Here is the code implementation.
```rust
impl DraftPost {
// --snip--
pub fn request_review(self) -> PendingReviewPost {
PendingReviewPost {
content: self.content,
}
}
}
pub struct PendingReviewPost {
content: String,
}
impl PendingReviewPost {
pub fn approve(self) -> Post {
Post {
content: self.content,
}
}
}
```
Here the `request_review` and `approve` methods take ownership of `self`.
This thus consumes the `DraftPost` and `PendingReviewPost` instances and transforming them into a `PendingReviewPost` and a published `Post`.
This way we will not have any lingering `DraftPost` instances after we called `request_review` on them and so on.
The `PendingReviewPost` struct also doesn't have a `content` method defined on it.
Again attempting to read its content results in a compiler error.
Because the only way to get a published `Post` instance that does have a `content` method defined is to call the `approve` method on a `PendingReviewPost`, and the only way to get a `PendingReviewPost` is to call the `request_review` method on a `DraftPost`.
Now we have encoded the blog post workflow into the type system.
We also have to make some changes to `main`.
The `reequest_review` and `approve`methods return new instances rather than modifying the struct they are called on.
We need to add more `let post =` shadowing assignments to save the returned instances.
We also can't have assertions about the draft and pending review posts' contents being empty strings, nor do we need them.
We are unable to compile any code that tires to use the content of posts in those states any longer.
Here is the updated code in `main`
```rust
use blog::Post;
fn main() {
let mut post = Post::new();
post.add_text("I ate a salad for lunch today");
let post = post.request_review();
let post = post.approve();
assert_eq!("I ate a salad for lunch today", post.content());
}
```
The changes we need to make to `main` to reassign `post` mean that this implementation doesn't quite follow the object oriented state pattern anymore.
The transformations between the states are no longer encapsulated entirely within the `Post` implementation.
However our gain is that invalid states are now impossible because of the type system and the type checking that happens at compile time.
This enforces that certain bugs, such as display of the content of an unpublished post, will be discovered before they make it production.
Try the tasks suggested before on the `blog` crate as it is after to see what you think about the design of this version of the code.
Note that some of the tasks might be completed already in this design.
We have seen that even though Rust is capable of implementing object-oriented design patterns, other patterns such as encoding state into the type system, are also available in Rust.
These patterns have different trade0ffs.
While you may be very familiar with object-oriented patterns, rethinking the problem to take advantage of Rust's features can provide benefits, such as preventing some bugs due to certain features, like ownership, that object-oriented languages don't have.

502
Macros.md Normal file
View File

@ -0,0 +1,502 @@
# Macros
The term *macro* refers to a family of features in Rust: *declarative* macros with `macro_rules!` and three kinds of *procedural* macros:
- Custom `#[derive]` macros that specify code added with the `derive` attribute used on structs and enums.
- Attribute-like macros that define custom attributes usable on any item
- Function-like macros that look like function calls but operate on the tokens specified as their argument
Each will be discussed, but let's first look at why we even need macros when we already have functions.
## The Difference Between Macros and Functions
Fundamentally macros are a way of writing code that writes other code, which is known as *metaprogramming*.
In Appendix C, we discuss the `derive` attribute, which generates an implementation of various traits for you.
All of these macros *expand* to produce more code than the code you have written manually.
Metaprogramming is useful for reducing the amount of code you have to write and maintain, which is also one of the roles of functions.
Macros have some additional powers that functions don't have.
A function signature must declare the number and type of parameters the function has.
Macros can take a variable number of parameters.
To show this: we can call `println!("hello")` with one argument or `println!("hello {}", name)` with two arguments.
Macros are also expanded before the compiler interprets the meaning of the code, so a macro can.
For example, implement a trait on a give type.
A function cannot, because it gets called at runtime and a trait needs to be implemented at compile time.
The downside to implementing a macro instead of a function is that macro definition are more complex than function definitions because you are writing Rust code that writes Rust code.
This indirection of macro definitions are generally more difficult to read, understand and maintain than function definitions.
Another important difference between macros and functions is that you must define macros or bring them into scope *before* you call them in a file.
This is opposed to functions where you can define anywhere and call anywhere.
## Declarative Macros with `macro_rules!` for General Metaprogramming
The most widely used form of macros in Rust is the *declarative macro*.
These are sometimes also referred to as "macros by example," *"`macro rules` macros"* or just plain "macros."
At their core, declarative macros allow you to write something similar to a Rust `match` expression.
`match` expressions are control structures that take an expression, compare the resulting value of the expression to patterns, and then run the code associated with the matching pattern.
Macros also compare a value to patterns that are associated with particular code.
In this situation, the value is the literal Rust source code passed to the macro, the patterns are compared with the structure of that source code and the code associated with each pattern, when matched, replaces the code passed to the macro.
This happens during compilation.
In order to define a macro, you use the `macro_rules!` construct.
Now lets explore how to use `macro_rules!` by looking at how the `vec!` macro is defined.
Ch8 covered how we can use the `vec!` macro to create a new vector with particular values.
For example, the following macro creates a new vector containing three integers:
```rust
let v: Vec<u32> = vec![1, 2, 3];
```
We could also use the `vec!` macro to make a vector of two integers or a vector of five string slices.
We wouldn't be able to use a function to do the same because we wouldn't know the number or type values up front.
Here shows a slightly simplified definition of the `vec!` macro.
```rust
#[macro_export]
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
```
Note: The actual definition of the `vec!` macro in std library includes code to preallocate the correct amount of memory up front.
That code is an optimization that we don't include here to make the example simpler.
The `#[macro_export]` annotation indicates that this macro should be made available whenever the crate in which the macro is defined is brought into scope.
We then start the macro definition with `macro_rules!` and the name of the macro we are defining *without* the exclamation mark.
Then name here `vec` is followed by curly brackets denoting the body of the macro definition.
The structure in the `vec!` body is similar to the structure of a `match` expression.
Here we have one arm with the pattern `( $( $x:expr ),* )`, followed by `=>` and the block of code associated with this pattern.
If the pattern matches, the associated block of code will be emitted.
Given this is the only pattern in this macro, there is only one valid way to match; any other pattern will result in an error.
More complex macros will have more than one arm.
Valid pattern syntax in macro definitions is different than the pattern syntax covered in Ch19.
This is because macro patterns are matched against Rust code structure rather than values.
Now lets go over what the pattern pieces in the previous examples mean.
The full macro pattern syntax can be seen in the [Rust Reference](https://doc.rust-lang.org/reference/macros-by-example.html).
First, we use a set of parentheses to encompass the whole pattern.
We use a dollar sign (`$`) to declare a variable in the macro system that will contain the Rust code matching the pattern.
The dollar sign makes it clear this a macro variable as opposed to a regular Rust variable.
Next comes a set of parentheses that captures values that match the pattern within the parentheses for use in the replacement code.
Within `$()` is `$x: expr`, this matches any Rust expression and gives the expression the name `$x`.
The comma following `$()` indicates that a literal comma separator character must appear between each instance of the code that matches the code within `$()`.
The `*` specifies that the pattern matches zero or more of whatever precedes the `*`.
When we call this macro with `vec![1, 2, 3];`, the `$x` pattern matches three times with the three expressions `1`, `2`, and `3`.
Now lets look at the pattern in the body of the code associated with this arm: `temp_vec.push()` within `$()*` is generated for each part that matches `$()` in the pattern zero or more times depending on how many times the pattern matches.
The `$x` is replaced with each expression matched.
When we call this macro with `vec![1, 2, 3];` the code generated that replaces this macro call will be this:
```rust
{
let mut temp_vec = Vec::new();
temp_vec.push(1);
temp_vec.push(2);
temp_vec.push(3);
temp_vec
}
```
Here we dined a macro that can take any number of arguments of any type and can generate code to create a vector containing the specified elements.
To learn more about how to write macros, read online documentation or other resources like ["The Little Book of Rust Macros"](https://veykril.github.io/tlborm/) started by Daniel Keep and continued by Lukas Wirth.
## Procedural Macros for Generating Code from Attributes
The second form of macros is the *procedural macro*, which acts more like a function (and is a type of procedure).
Procedural macros accept some code as an input, operate on this code, and produce some code as an output rather than matching against patterns and replacing the code with other code as declarative macros do.
The three kinds of procedural macros are custom derive, attribute-like and function-like and all work in a similar way.
When creating procedural macros, the definitions must reside in their own crate with a special enum crate type.
This is for complex technical reasons that the Rust team hopes to eliminate in the future.
Here we show how to define a procedural macro, where `some_attribute` is placeholder for using a specific macro variety.
```rust
use proc_macro;
#[some_attribute]
pub fn some_name(input: TokenStream) -> TokenStream {
}
```
This function that defines a procedural macro takes `TokenStream` as an input and produces a `TokenStream` as an output.
The `ToeknnStream` type is defined by the `proc_macro` crate that is included with Rust and represents a sequence of tokens.
This is the core of the macro: the source code that the macro is operating on makes up the input `TokenStream` and the code the macro produces is the output `TokenStream`.
This function also has an attribute attached to it which specifies what kind of procedural macro we are creating.
We can have multiple kinds of procedural macros in the same crate.
Now we will look at the different kinds of procedural macros.
First we will start with a custom derive macro and then go on to explain the small dissimilarities that make the other forms different.
## How to Write a Custom `derive` Macro
Lets start with a crate named `hello_macro` which defines a trait named `HelloMacro` with one associated function named `hello_macro`.
Rather than forcing our users to implement the `HelloMacro` trait for each of their types, we will provide a procedural macro so users can annotate their type with `#[derive(HelloMacro)]` to get a default implementation of the `hello_macro` function.
The default implementation will print `Hello, Macro! My name is TypeName!` where `TypeName` is the name of the type which this trait has been defined.
We will write a crate that enables another programmer to write code like this below using our crate.
```rust
use hello_macro::HelloMacro;
use hello_macro_derive::HelloMacro;
#[derive(HelloMacro)]
struct Pancakes;
fn main() {
Pancakes::hello_macro();
}
```
This will print `Hello, Macro! My name is Pancakes!` when we are done.
The first step will be to make a new library crate using this:
```
$ cargo new hello_macro --lib
```
Then we will define the `HelloMacro` trait and its associated function.
```rust
pub trait HelloMacro {
fn hello_macro();
}
```
*src/lib.rs*
We have a trait and its function.
Now at this point our crate user could implement the trait to achieve the desired functionality, like this:
```rust
use hello_macro::HelloMacro;
struct Pancakes;
impl HelloMacro for Pancakes {
fn hello_macro() {
println!("Hello, Macro! My name is Pancakes!");
}
}
fn main() {
Pancakes::hello_macro();
}
```
However they would need to write the implementation block for each type they wanted to use with `hello_macro`.
We want to spare them from having to do this.
Additionally, we can't yet provide the `hello_macro` function with default implementation that will print the name of the type the trait is implemented on.
Rust doesn't have reflection capabilities, so it cannot look up the type's name at runtime.
Instead we need a macro to generate code at compile time.
Next is to define the procedural macro.
At the time of writing this, procedural macros need to be in their own crate.
The convention for structuring crates and macro crates is as follows.
For a crate named `foo`, a custom derive procedural macro crate is called `foo_derive`.
Now lets start a new crate called `hello_macro_derive` inside our `hello_macro` project.
```
$ cargo new hello_macro_derive --lib
```
The two crates are tightly related, so we create the procedural macro crate within the directory of our `hello_macro` crate.
If we change the trait definition in `hello_macro`, we will have to change the implementation of the procedural macro in `hello_macro_derive` as well.
The two crates will need to be published separately, and programmers using these crates will need to add both as dependencies and bring them both into scope.
We instead could have the `hello_macro` crate use `hello_macro_derive` as a dependency and re-export the procedural macro code.
The way we have structured the project makes it possible for programmers to use `hello_macro` even if we don't want the `derive` functionality.
We need to declare the `hello_macro_derive` crate as a procedural macro crate.
We also need functionality form the `syn` and `quote` crates.
So we need to add them as dependencies.
Add this to the *Cargo.toml* file for the `hello_macro_derive`.
```toml
[lib]
proc-macro = true
[dependencies]
syn = "2.0"
quote = "1.0"
```
To start defining the procedural macro, place the code into your *src/lib.rs* file for the `hello_macro_derive` crate.
Note that this code will not compile unless we add a definition for the `impl_hello_macro` function.
```rust
use proc_macro::TokenStream;
use quote::quote;
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
let ast = syn::parse(input).unwrap();
// Build the trait implementation
impl_hello_macro(&ast)
}
```
*hello_macro_derive/src/lib.rs*
Note that we have split the code into the `hello_macro_derive` function, which is responsible for parsing the `TokenStream` and the `impl_hello_macro` function, which is responsible for transforming the syntax tree.
This makes writing a procedural macro more convenient.
The code in the outer function (`hello_macro_dervie` in this case) will be the same for almost every procedural macro crate you see or create.
The code specified in the body of the inner function (`impl_hello_macro` in this case) will be different depending on your procedural macro's purpose.
We have introduced three new crates: `proc_macro`, [`syn`](https://crates.io/crates/syn), and [`quote`](https://crates.io/crates/quote).
The `proc_macro` crate comes with Rust, so we don't need to add that to the dependencies in *Cargo.toml*.
The `proc_macro` crate is the compiler's API that allows us to read and manipulate Rust code from our code.
The `syn` crate parses Rust code form a string into a data structure that we can perform operations on.
The `quote` crate turns `syn` data structures back into Rust code.
These crate makes it much simpler to parse any sort of Rust code we might want to handle: writing a full parser for Rust code is no simple task.
The `hello_macro_derive` function will be called when a user of our library specifies `#[derive(HelloMacro)]` on a type.
This is possible because we have annotated the `hello_macro_derive` function here with `proc_macro_derive` and specified the name `HelloMaro`.
This matches our trait name, this is the convention most procedural macros follow.
The `hello_macro_derive` function first converts the `input` from a `TokenStream` to a data structure that we can then interpret and perform operations on.
This is where `syn` comes into aciton.
The `parse` function in `syn` takes a `TokenStream` and shows the relevant parts of the `DeriveInput` struct we get form parsing the `struct Pancakes;` string.
```rust
DeriveInput {
// --snip--
ident: Ident {
ident: "Pancakes",
span: #0 bytes(95..103)
},
data: Struct(
DataStruct {
struct_token: Struct,
fields: Unit,
semi_token: Some(
Semi
)
}
)
}
```
The fields of this struct show that the Rust code we have parsed is a unit struct with the `ident` (identifier, this means the name) of `Pancakes`.
There are more fields on this struct for describing all kinds of Rust code.
Check the [`syn` documentation for `DeriveInput`](https://docs.rs/syn/2.0/syn/struct.DeriveInput.html) for more info.
Soon the `impl_hello_macro` function will be defined, which is where we will build the new Rust code we want to include.
Before we do this.
Note that the output for our derive macro is also a `TokenStream`.
The returned `TokenStream` is added to the code that our crate users write, so when they compile their own crate, they will get the extra functionality that we will provide in the modified `TokenStream`.
You may have noticed that we are calling `unwrap` to cause the `hello_macro_derive` function to panic if the call to the `syn::parse` function fails.
This is necessary for our procedural macro to panic on errors because `proc_macro_derive` functions must return `TokenStream` rather than `Result` to conform to the procedural macro API.
Here we have simplified this example by using `unwrap`; in production you should provide more specific error messages about what went wrong by using `panic!` or `expect`.
Note that we have the code to turn the annotated Rust code from a `TokenStream` into a `DeriveInput` instance.
Now we will generate the code that implements the `HelloMacro` trait on the annotated type.
This is shown here.
```rust
fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("Hello, Macro! My name is {}!", stringify!(#name));
}
}
};
gen.into()
}
```
We get an `Ident` struct instance containing the name (identifier) of the annotated type using `ast.idetn`.
The struct before shows that when we run the `impl_hello_macro` function on the code form before that.
The `ident` we get will have the `ident` field with a value of `"Pancakes"`.
The `name` variable here will contain an `Ident` struct instance that, when printed will be the string `"Pancakes"`, the name of the struct from way before.
The `quote!` macro lets us define the Rust code that we want to return.
The compiler expects something different to the direct result of the `quote!` macro's execution, so we need to convert it to a `TokenStream`.
We do this by calling the `into` method, this consumes this intermediate representation and returns a value of the required `TokenStream` type.
The `quote!` macro also provides some very interesting templating mechanics.
We can enter `#name` and `quote!` will replace it with the value in the variable `name`.
You can even do some repetition similar to the way regular macros work.
Check the [`quote` crate's docs](https://docs.rs/quote) for a thorough introduction.
We want our procedural macro to generate an implementation of our `HelloMacro` trait for the type the user annotated, which we can get by using `#name`.
The trait implementation has the one function has the one function `hello_macro`, whose body contains the functionality we want to provide.
Printing `Hello, Macro! My name is` and then the name of the annotated type.
The `stringify!` macro used here is built into Rust.
This takes a Rust expression, such as `1 + 2`, and at compile time turns the expression into a string literal, such as `"1 + 2"`.
This is different than `format!` or `println!`, macros which evaluate the expression and then turn the result into a `String`.
It is possible that the `#name` input may be an expression to print literally, so we use `stringify!`.
Using `stringify!` also saves an allocation by converting `#name` to a string literal at compile time.
Now at this point, `cargo build` should complete successfully in both `hello_macro` and `hello_macro_derive`.
Now we will hook these crates to the code from before to see the procedural macro in action.
Create a new binary project in your *projects* directory using `cargo new pancakes`.
We need to add `hello_macro` and `hello_macro_derive` as dependencies in the `pancakes` crate's *Cargo.toml*.
If you are publishing your versions of `hello_macro` and `hello_macroderive` to [crates.io](https://crates.io) they would be regular dependencies.
If not you can specify them as `path` dependencies as follows:
```toml
hello_macro = { path = "../hello_macro" }
hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }
```
Now you can put the code from way before into *src/main.rs*, and run `cargo ran`.
It should print `Hello, Macro! My name is Pancakes!`.
The implementation of the `HelloMacro` trait form the procedural macro was included without the `pancakes` crate needing to implement it.
The `#[derive(HelloMacro)]` added the trait implementation.
## Attribute-like macros
These kinds of macros are similar to custom derive macros, but instead of generating code for the `derive` attribute, they allow you to create new attributes.
They are also more flexible: `derive` only works for structs and enums.
Attributes can be applied to other items as well, such functions.
Here is an example of using an attribute-like macro: say you have an attribute named `route` that annotates functions when using a web application framework.
```rust
#[route(GET, "/")]
fn index() {
```
This `#[route]` attribute would defined by the framework as a procedural macro.
The signature of the macro definition function would look like this:
```rust
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
```
Here, we have two parameters of type `TokenStream`.
The first is for the contents of the attribute: the `GET, "/"` part.
The second is the body of the item the attribute is attached to: here it is `fn index() {}` and the rest of the function's body.
Other than that, attribute-like macros work the same way as custom derive macros.
You create a crate with the `proc-macro` crate type and implement a function that generates the code you want.
## Function-like macros
Function-like macros define macros that look like function calls.
This is similar to `macro_rules!` macros.
They are more flexible than functions.
For example they can take an unknown number of arguments.
However `macro_rules!` macros can be defined only using the match-like syntax that was discussed in the [ “Declarative Macros with `macro_rules!` for General Metaprogramming"](./Macros.md#declarative-macros-with-macro_rules-for-general-metaprogramming) section from earlier before.
Function-like macros take a `TokenStream` parameter and their definition manipulates that `TokenStream` using Rust code as the other two types of procedural macros do.
Here is an example of a function-like macro is an `sql!` macro that may be called like this:
```rust
let sql = sql!(SELECT * FROM posts WHERE id=1);
```
This macro would parse the SQL statement inside it and check that is syntactically correct.
This is much more complex processing than a `macro_rules!` macro can do.
The `sql!` macro would be defined like this:
```rust
#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {
```
The definition is similar to the custom derive macro's signature: we receive the tokens that are inside the parentheses and return the code we wanted to generate.
s

View File

@ -0,0 +1,16 @@
# Object-Oriented Programming Features of Rust
OOP is a way of modeling programs.
Objects as a programmatic concept were introduced in the programming language Simula in the 1960s.
These objects influenced Alan Kay's programming architecture in which objects pass messages to each other.
To describe this architecture, he coined the term *object-oriented programming* in 1967.
Many competing definitions describe what OOP is, and by some of these definitions Rust is object-oriented, but by other it is not.
In this section, we will explore certain characteristics that are commonly considered object-oriented and how those characteristics translate to idiomatic Rust.
Next we will show how to implement an object-oriented design pattern in Rust and discuss the trade-offs of doing so.
Versus implementing a solution using some of Rust's strengths instead.

44
Pattern Matching.md Normal file
View File

@ -0,0 +1,44 @@
# Patterns and Matching
*Patterns* are a special syntax in Rust for matching against the structure of types, both complex and simple.
Using patterns in conjunction with `match` expressions and other constructs give you more control over a program's flow.
A pattern consists of some combination of the following:
- Literals
- Destructured arrays, enums, structs, or tuples
- Variables
- Wildcards
- Placeholders
Some examples include `x`, `(a, 3)` and `Some(Color::Red)`.
In the contexts in which patterns are valid, these components describe the shape of data.
Our program then matches values against the patterns to determine whether it has the correct shape of data to continue running a particular piece of code.
In order to use a pattern, we compare it to some value.
If the pattern matches the value, we use the value parts in our code.
Recall the `match` expression that used patterns, such as the coin-sorting machine example.
If the value fits the shape of the pattern, we can use the named pieces.
If it doesn't, the code associated with the pattern won't run.
This chapter is intended to be a reference on all things related to patterns.
We will cover:
- Valid places to use patterns [Section Link Here]()
- Difference between refutable and irrefutable patterns [Section Link Here](./Refutability.md)
- Different kinds of pattern syntax [Section Link Here](./Pattern%20Syntax.md)
By the end you will know how to use patterns to express many concepts in a clear way.
## Summary
Patterns are very useful in distinguishing between different kinds of data.
When used in `match` expressions, Rust ensures your patterns cover every possible value, or your program will not compile.
Patterns in `let` statements and function parameters make those constructs more useful, enabling the destructuring of values into smaller parts at the same time as assigning to variables.
Then we can create simple or complex patterns to suit our needs.

686
Pattern Syntax.md Normal file
View File

@ -0,0 +1,686 @@
# Pattern Syntax
Here we gather all the syntax valid in patterns and discuss why and when you might want to use each one.
## Matching Literals
As you saw previously in Ch6, you can match patterns against literals directly.
Here is an example of this
```rust
let x = 1;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("anything"),
}
```
The code prints `one` because the value in `x` is 1.
This syntax is useful when you want your code to take an action if it gets a particular concrete value.
## Matching Named Variables
Named variables are irrefutable patterns that match any value, and we have used them many times.
However, there is a complication when you use named variables in `match`, `if let`, or `while let` expressions.
Because each kinds of expression starts a new scope, variables declared as part of a pattern inside the expression will shadow those with the same name outside, as is the case with all variables.
Here we declare a variable named `x` with the value `Some(5)` and a variable `y` with the value `10`.
Next we create a `match` expression on the value `x`.
Look at the patterns in the match arms and `println!` at the end, and try to figure out what the code will print before running this code or reading further.
```rust
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50"),
Some(y) => println!("Matched, y = {y}"),
_ => println!("Default case, x = {x:?}"),
}
println!("at the end: x = {x:?}, y = {y}");
```
Lets run through what happens when the `match` expression runs.
The pattern in the first match arm doesn't match the defined value of `x`, so the code continues.
The pattern in the second match arm introduces a new variable named `y` that will match any value inside a `Some` value.
Because we are in a new scope inside the `match` expression, this is a new `y` variable, not the `y` we declared at the beginning with the value 10.
This new `y` binding will match any value inside a `Some`, which is what we have in `x`.
Therefore the new `y` binds to the inner value of the `Some` in `x`.
That value is `5` so the expression for that arm executes and prints `Matched , y = 5`.
If `x` has been a `None` value instead of `Some(5)`, the patterns in the first two arms wouldn't have matched. so the value would have matched to the underscore.
We didn't introduce the `x` variable in the pattern of the underscore arm, so the `x` in the expression is still the outer `x` that hasn't been shadowed.
For this hypothetical case, the `maatch` would pint `Default case, x = None`.
When the `match` expression is done, its scope ends, and so does the scope of the inner `y`.
The last `println!` produces `at the end: x = Some(5), y = 10`.
To create a `match` expression that compares the values of the outer `x` and `y` rather than introducing a new variable which shadows the exiting `y` variable.
We would need to use a match guard conditional instead.
This will be covered later in the ch.
## Multiple Patterns
You can match multiple patterns using the `|` syntax, which is the pattern *or* operator.
For example in the following code we match the value of `x` against the match arms, the first of which has an *or* option, meaning if the value of `x` matches either of the values in that arm, that arm's code will run
```rust
let x = 1;
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
_ => println!("anything"),
}
```
This code prints `one or two`.
## Matching Ranges of Values with `..=`
The `..=` syntax allows us to match to an inclusive range of values.
Here when a pattern matches any of the values within the given range, that arm will execute
```rust
let x = 5;
match x {
1..=5 => println!("one through five"),
_ => println!("something else"),
}
```
If `x` is 1, 2, 3, 4, or 5, the first arm will match.
This syntax is more convenient for multiple match values that using the `|` operator to express the same idea.
If we were to use `|` we would need to do `1 | 2 | 3 | 4 | 5`.
Specifying a range is much shorter, especially if we want to match, say any number between 1 and 1,000.
The compiler checks that the range isn't empty at compile time, because only types for which Rust can tell if a range is empty or not are `char` and numeric values, ranges are only allowed with numeric or `car` values.
Rust can tell that `'c'` is within the first pattern's range and prints `early ASCII letter`.
## Destructuring to Break Apart Values
We can also use patterns to destructure structs, enums, and tuples to use different parts of these values.
We will walk through each value.
### Destructuring Structs
This code shows a `Point` struct with two fields, `x` and `y`, that we can break apart using a patter with a `let` statement
```rust
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 0, y: 7 };
let Point { x: a, y: b } = p;
assert_eq!(0, a);
assert_eq!(7, b);
}
```
This creates the variables `a` and `b` that match the values of the `x` and `y` fields of the `p` struct.
This shows that the names of the variables in the pattern don't have to match the field names of the struct.
However it is common to match the variable names to the field names to make it easier to remember which variables came from which fields.
Because of this common usage, and because writing `let Point { x: x, y: y} = p;` contains a lot of duplication, Rust has a shorthand for patterns that match struct fields.
You only need to list the name of the struct field, and the variables created from the pattern will have the same names.
This code behaves in the same way as om the code before, but the variables created in the `let` pattern are `x` and `y` instead of `a` and `b`.
```rust
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 0, y: 7 };
let Point { x, y } = p;
assert_eq!(0, x);
assert_eq!(7, y);
}
```
This code creates the variables `x` and `y` that match the `x` and `y` fields of the `p` variable.
The outcome is that the variables `x` and `y` contain the values form the `p` struct.
We can also destructure with literal values as part of the struct pattern rather than creating variables for all the fields.
Doing this allows us to test some of the fields for particular values while creating variables to destructure the other fields.
Here we have a `match` expression that separates `Point` values into three cases.
Points that lie directly on the `x` axis (which is true when `y = 0`)
On the `y` axis (`x = 0`)
Or Neither
```rust
fn main() {
let p = Point { x: 0, y: 7 };
match p {
Point { x, y: 0 } => println!("On the x axis at {x}"),
Point { x: 0, y } => println!("On the y axis at {y}"),
Point { x, y } => {
println!("On neither axis: ({x}, {y})");
}
}
}
```
The first arm will match any point that lies on the `x` axis by specifying that the `y` field matches if its value matches the literal `0`.
The pattern still creates an `x` variable that we can use in the code for this arm.
The second arm matches any point on the `y` axis by specifying that the `x` field matches if its value is `0` and creates a variable `y` for the value of the `y` field.
The third arm doesn't specify any literals, so it matches any other `Point` and creates variables that we can use in the code for this arm.
Here the value `p` matches the second arm by virtue of `x` containing a 0, so this code will print `On the x axis at 0`.
### Destructuring Enums
We have destructured enums before, but haven't explicitly discussed that the pattern to destructure an enum corresponds to the way the data stored within the enum is defined.
For example, here we use the `Message` enum from Ch6 and write a `match` with patterns that will destructure each inner value.
```rust
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msg = Message::ChangeColor(0, 160, 255);
match msg {
Message::Quit => {
println!("The Quit variant has no data to destructure.");
}
Message::Move { x, y } => {
println!("Move in the x direction {x} and in the y direction {y}");
}
Message::Write(text) => {
println!("Text message: {text}");
}
Message::ChangeColor(r, g, b) => {
println!("Change the color to red {r}, green {g}, and blue {b}");
}
}
}
```
This code will print `Change the color to red 0, green 160, and blue 255`.
Try changing the value of `msg` to see the code form the other arms run.
For enum variants without any data, like `Message::Quit`.
We can't destructure the value any further.
We can only match on the literal `Message::Quit` value and no variables are in that pattern.
For struct-like enum variants, like `Message::Move`.
We can use a pattern similar to the pattern we specify to match structs.
After the variant name, we place curly brackets and then list the fields with variable so we break apart the pieces to use in the code for this arm.
We did use the shorthand form as we did before.
For tuple-like enum variants, like `Message::Write` that holds a tuple with one element and `Message::ChangeColor` that holds a tuple with three elements.
The pattern is similar to the pattern we specify to match tuples.
The number of variables in the pattern must match the number of elements in the variant we are matching.
### Destructuring Nested Structs and Enums
So we have seen examples that have all been matching structs or enums on level deep.
Matching can work on nested items too.
For example, we can refactor the code form before to support RGB and HSV colors in the `ChangeColor` message.
```rust
enum Color {
Rgb(i32, i32, i32),
Hsv(i32, i32, i32),
}
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(Color),
}
fn main() {
let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));
match msg {
Message::ChangeColor(Color::Rgb(r, g, b)) => {
println!("Change color to red {r}, green {g}, and blue {b}");
}
Message::ChangeColor(Color::Hsv(h, s, v)) => {
println!("Change color to hue {h}, saturation {s}, value {v}");
}
_ => (),
}
}
```
The first arm in the `match` expression, matches a `Message::ChangeColor` enum variant that contains a `Color::Rgb` variant.
Then the pattern binds to the three inner `i32` values.
The second arm also matches a `Message::ChangeColor` enum variant, but the inner enum matches `Color::Hsv` instead.
We can specify these complex conditions in one `match` expression, even though two enums are involved.
### Destructuring Structs and Tuples
We can also mix, match and nest destructuring patterns in even more complex ways.
This example shows a complicated destructure where we nest structs and tuples inside a tuple and destructure all the primitive values out
```rust
let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });
```
Here the code lets us break complex types into their component parts so we can use the values we are interested in separately.
Destructuring with patters is a convenient way to use pieces of values such as the value from each field in a struct, separately from each other.
## Ignoring Values in a Pattern
Sometimes it is useful to ignore values in a pattern, such as in the last arm of a `match`, to get a catchall that doesn't actually do anything but does account for all remaining possible values.
There are a few ways to ignore entire values or pats of values in a pattern:
- Using the `_` pattern
- Using the `_` pattern within another pattern
- Using a name that starts with an underscore
- Using `..` to ignore remaining parts of a value.
### Ignoring an Entire Value with `_`
We have used the underscore as a wildcard pattern that will match any value but not bind to the value.
This is particularly useful as the last arm in a `match` expression.
We can also use it in any pattern, including function parameters
```rust
fn foo(_: i32, y: i32) {
println!("This code only uses the y parameter: {y}");
}
fn main() {
foo(3, 4);
}
```
This will completely ignore the value `3` that is passed as the first argument.
You will print `This code only uses the y parameter: 4`.
In most cases when you no longer need a particular function parameter, you would change the signature so it doesn't include the used parameter.
Ignoring a function parameter can be especially useful in cases when you are implementing a trait when you need a certain type signature but the function body in your implementation doesn't need one of the parameters.
Thus then you avoid getting a compiler warning about unused function parameters, as you would if you used a name instead.
### Ignoring Parts of a Value with a Nested `_`
You can also use `_` inside another pattern to ignore just part of a value.
Lets say when you want to test for only part of a value but have no use for the other parts in the corresponding code we want to run.
Here shows code responsible for managing a setting's value.
The business requirements are that the user should not be allowed to overwrite an existing customization of setting but can unset the setting and give it a value if it is currently unset.
```rust
let mut setting_value = Some(5);
let new_setting_value = Some(10);
match (setting_value, new_setting_value) {
(Some(_), Some(_)) => {
println!("Can't overwrite an existing customized value");
}
_ => {
setting_value = new_setting_value;
}
}
println!("setting is {setting_value:?}");
```
This will print `Can't overwrite an existing customized value` and then `setting is Some(5)`.
In the first arm, we don't need to match on or use the values inside either `Some` variant, but we do need to test for the case when `setting_value` and `new_setting_value` are the `Some` variant.
In this case, we print the reason for not changing `setting_value`, and it doesn't get changed.
In all other cases (if either `setting_value` or `new_setting_value` are `None`) expressed by the `_` pattern in the second arm.
We want to allow `new_setting_value` to become `setting_value`.
We could also use underscores in multiple places within one pattern to ignore particular vlaues.
Here shows an example of ignoring the second and fourth values in a tuple of five items.
```rust
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, _, third, _, fifth) => {
println!("Some numbers: {first}, {third}, {fifth}")
}
}
```
This will print `Some numbers: 2, 8, 32`, and the values 4 and 16 will be ignored.
### Ignoring an Unused Variable by Starting Its Name with `_`
If you create a variable but don't use it anywhere, Rust will usually issue a warning because an unused variable could be a bug.
However sometimes it is useful to be able to create a variable you will not use yet.
Such as when you are prototyping or just starting a project.
In this situation, you can tell Rust not to warn you about the unused variable by starting by starting the name of the variable with an underscore.
Here we create two unused variables, but when we compile, we should only get warning about one of them.
```rust
fn main() {
let _x = 5;
let y = 10;
}
```
We get a warning about not using the variable `y`, but we don't get a warning about not using `_x`.
The only difference between using only `_` and using a name that starts with an underscore.
The syntax `_x` still binds the value to the variable, whereas `_` doesn't bind at all.
To show a case where this distinction matters, this will provide us with an error.
```rust
let s = Some(String::from("Hello!"));
if let Some(_s) = s {
println!("found a string");
}
println!("{s:?}");
```
We will receive an error because the `s` value will still be moved into `_s`, which prevents us from using `s` again.
Using the underscore by itself doesn't ever bind to the value.
This code will compile without an errors because `s` doesn't get moved into `_`.
```rust
let s = Some(String::from("Hello!"));
if let Some(_) = s {
println!("found a string");
}
println!("{s:?}");
```
This code works just fine because we never bind `s` to anything; it isn't moved.
### Ignoring Remaining Parts of a Value with `..`
Values that have many parts, we can use the `..` syntax to use specific parts and ignore the rest, avoiding the need to list underscores for each ignored value.
The `..` pattern ignores any parts of a value that we haven't explicitly matched in the rest of the pattern.
In this code we have a `Point` struct that holds a coordinate in three-dimensional space.
In this `match` expression, we want to operate only on the `x` coordinate and ignore the values in the `y` and `z` fields.
```rust
struct Point {
x: i32,
y: i32,
z: i32,
}
let origin = Point { x: 0, y: 0, z: 0 };
match origin {
Point { x, .. } => println!("x is {x}"),
}
```
Here we list the `x` value and then just include the `..` pattern.
This is far quicker than having to list `y: _` and `z: _`, particularly when we are working with structs that have lots of fields in situations where only one or two fields are relevant.
The syntax `..` will expand to as many values as it needs to be.
This is an example of how to use `..` with a tuple.
```rust
fn main() {
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, .., last) => {
println!("Some numbers: {first}, {last}");
}
}
}
```
Output
```
Some numbers: 2, 32
```
The fist and last value are matched with `first` and `last`.
The `..` will match and ignore everything in the middle.
Using `..` must be unambiguous.
If it unclear which values are intended for matching and which should be ignored, Rust will give us an error.
Here shows an example of using `..` ambiguously, so it will not compile.
```rust
fn main() {
let numbers = (2, 4, 8, 16, 32);
match numbers {
(.., second, ..) => {
println!("Some numbers: {second}")
},
}
}
```
We get this compiler error
```
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
error: `..` can only be used once per tuple pattern
--> src/main.rs:5:22
|
5 | (.., second, ..) => {
| -- ^^ can only be used once per tuple pattern
| |
| previously used here
error: could not compile `patterns` (bin "patterns") due to 1 previous error
```
It is impossible for Rust to determine how many values in the tuple to ignore before matching a value with `second` and then how many further values to ignore after.
This code could mean we want to ignore `2`, bind `second` to `4` and then ignore `8` and `16` and `32`.
Or it could mean we want to ignore `2` and `4`, bind `second` to `8`, and then ignore `16` and `32`.
Or any other case.
The variable name `second` doesn't mean anything special to Rust, we get a compiler error because using `..` in two places like this ambiguous.
## Extra Conditionals with Match Guards
A *match guard* is an additional `if` condition, specified after the pattern in a `match` arm, that must also match for that arm to be chosen.
Match guards are useful for expressing complex ideas than a pattern alone allows.
They are only available in `match` expressions, not in `if let` or `while let` expressions.
The condition can use variables created in the pattern.
Here shows a `match` where the first arm has the pattern `Some(x)` and also has a match guard of `if x % 2 == 0`
This will be true if the number is even.
```rust
let num = Some(4);
match num {
Some(x) if x % 2 == 0 => println!("The number {x} is even"),
Some(x) => println!("The number {x} is odd"),
None => (),
}
```
This will print `The number 4 is even`.
When `num` is compared to the pattern in the first arm, it matches.
This is because `Some(4)` matches `Some(x)`.
Next the match guard checks whether the remainder of dividing `x` by 2 is equal to 0.
Because this is true the first arm is selected.
If `num` had been `Some(5)` instead, the match guard in the first arm would have been false.
This is because the remainder of 5 / 2 is 1, which is not equal to 0.
Rust would then go to the second arm, which doesn't have a match guard and therefore matches any `Some` variant.
There is not may to express the `if x % 2 == 0` condition within a pattern, so the match guard gives us the ability to express this logic.
The downside of this is that the compiler doesn't try to check for exhaustiveness when match guard expressions are involved.
Before we mentioned that we could use match guards to solve our pattern shadowing problem.
Recall that after we created a new variable inside the pattern in the `match` expression instead of using the variable outside the `match`.
This new variable meant we couldn't test against the value of the outer variable.
Here shows how we can use match guard to fix this problem.
```rust
fn main() {
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50"),
Some(n) if n == y => println!("Matched, n = {n}"),
_ => println!("Default case, x = {x:?}"),
}
println!("at the end: x = {x:?}, y = {y}");
}
```
Output
```
Default case, x = Some(5)
at the end: x = Some(5), y = 10
```
The pattern in the second match arm doesn't introduce a new variable `y` that would shadow the outer `y`.
This means that we can use the outer `y` in the match guard.
Instead of specifying the pattern as `Some(y)`, which would have shadowed the outer `y`, we specify `Some(n)`.
This creates a new variable `n` that doesn't shadow anything because there is no `n` variable outside the `match`.
The match guard `if n == y` is not a pattern and therefore doesn't introduce new variables.
This `y` *is* the outer `y` rather than a new `y` shadowing it.
We can look for a value that has the same value as the outer `y` by comparing `n` to `y`.
You can also use the *or* operator `|` in a match guard to specify multiple patterns.
The match guard condition will apply to all the patterns.
Here shows the precedence when combining a pattern uses `|` with a match guard.
The important part of this example is that the `if y` match guard applies to `4`, `5`, and `6`, even though it might look like `if y` only applies to `6`.
```rust
let x = 4;
let y = false;
match x {
4 | 5 | 6 if y => println!("yes"),
_ => println!("no"),
}
```
This match condition states that the arm only matches if the if the value of `x` is equal to `4`, `5`, or `6` *and* if `y` is `true`.
When this runs, the pattern of the first arm matches because `x` is `4`, but the match guard `if y` is false, so the first arm is not chosen.
The code then moves on to the second arm, which does match and this program prints `no`.
The reason is that the `if` condition applies to the whole pattern `4 | 5| 6`, not only to the last value `6`.
In other words, the precedence of a match guard in relation to a pattern behaves like this
```
(4 | 5 | 6) if y => ...
```
rather than this
```
4 | 5 | (6 if y) => ...
```
After running this, the precedence behavior is evident.
If the match guard applied only to the final value in the list of values specified using the `|` operator, the arm would have matched and the program would have printed `yes`.
## `@` Bindings
The *at* operator `@` lets us create a variable that holds a value at the same time as we are testing that value for a pattern match.
Here we want to test that a `Message::Hello` `id` field is within the range `3..=7`.
We also want to bind that value to the variable `id_variable` so we can use it in the code associated with the arm.
We could name this variable `id`, the same as the field, but for this example we will use a different name.
```rust
enum Message {
Hello { id: i32 },
}
let msg = Message::Hello { id: 5 };
match msg {
Message::Hello {
id: id_variable @ 3..=7,
} => println!("Found an id in range: {id_variable}"),
Message::Hello { id: 10..=12 } => {
println!("Found an id in another range")
}
Message::Hello { id } => println!("Found some other id: {id}"),
}
```
Output
```
Found an id in range: 5
```
By specifying `id_vaariable @` before the range `3..=7`, we are capturing whatever value matched the range while also testing that the value matched the range pattern.
In the second arm, where we only have a range specified in the pattern, the code associated with the arm doesn't have a variable that contains the actual value of the `id` field.
The `id` field's values could have been 10, 11, or 12, but the code that goes with the pattern doesn't know which it is.
The pattern code isn't able to use the value form the `id` field, this is due to us not saving the `id` value in a variable.
In the last arm, where we have specified a variable without a range, we do have the value available to use in the arm's code in the variable named `id`.
The reason is that we have used the struct field shorthand syntax.
But we haven't applied any test to the value in the `id` field in this arm, as we did with the first two arms.
Any value would match this pattern.
Using `@` lets us test a value and save it in a variable within one pattern.

View File

@ -0,0 +1,254 @@
# All the Places Patterns Can Be Used
Patterns pop up in a number of places in Rust.
You use them a lot without realizing it.
## `match` Arms
As discussed in Ch6, we can use patterns in the arms of `match` expressions.
`match` expressions are defined as the keyword `match`, a value to match on, and one or more match arms that consist of a pattern and an expression to run if the value matches that arm's pattern, like this:
```
match VALUE {
PATTERN => EXPRESSION,
PATTERN => EXPRESSION,
PATTERN => EXPRESSION,
}
```
Here is an example of a `match` expression from ch6 that matches on an `Option<i32>` value in the variable `x`:
```rust
match x {
None => None,
Some(i) => Some(i + 1),
}
```
The patterns in here are the `None` and `Some(i)` on the left of each arrow.
One requirement for `match` expression is that they need to be *exhaustive* in the sense that all possibilities for the value in the `match` expression must be accounted for.
One way to ensure you have covered every possibility is to have a catchall pattern for the last arm.
For example, a variable name matching any value can never fail and thus covers every remaining case.
The particular pattern `_` will match anything, but it never binds to a variable, so it is often used in the last match arm.
The `_` pattern in more detail in the ["Ignoring Values in a Pattern"]() section.
## Conditional `if let` Expressions
In Ch6 we discussed how to use `if let` expressions mainly as a shorter way to write the equivalent of a `match` that only matches o one case.
Optionally `if let` can have a corresponding `else` containing code to run if the pattern in the `if let` doesn't match.
In this example it shows that it is also possible to mix and match `if let`, `else if` and `else if let` expressions.
This gives us more flexibility than a `match` expression in which we can express only one value to compare with the patterns.
Rust doesn't require that the conditions in a series of `if let`, `else if`, `else if let` arms relate to each other.
This code determines what color to make your background based on a series of checks for several conditions.
For example, we have created variables with hardcoded values that a real program might receive form user input.
```rust
fn main() {
let favorite_color: Option<&str> = None;
let is_tuesday = false;
let age: Result<u8, _> = "34".parse();
if let Some(color) = favorite_color {
println!("Using your favorite color, {color}, as the background");
} else if is_tuesday {
println!("Tuesday is green day!");
} else if let Ok(age) = age {
if age > 30 {
println!("Using purple as the background color");
} else {
println!("Using orange as the background color");
}
} else {
println!("Using blue as the background color");
}
}
```
Output
```
Using purple as the background color
```
If the user specifies a favorite color, that color is used as the background.
If no color is specified and today is Tuesday, the background is green.
If the user specifies their age as a string and we can parse it as a number successfully, the color is either purple or orange depending on the value of the number.
If none of the conditions apply, the background is blue.
This conditional structure lets us support complex requirements.
You can see that `if let` can also introduce new variables which shadow existing variables in the same way that `match` arms can.
The line `if let Ok(age) = age` introduces a new `age` variable that contains the `Ok` variant, shadowing the existing `age` variable.
This means we need to place the `if age > 30` condition within that block.
We cannot combine these two conditions into `if let Ok(age) = age && age > 30`.
The new `age` we want to compare to 30 isn't valid until the new scope starts with the curly bracket.
The downside of using `if let` expressions is that the compiler doesn't check for exhaustiveness, whereas with `match` expressions it does.
If we omitted the last `else` block and therefore missed handling some cases, the compiler would not alert us to the possible logic bug.
## `while let` Conditional Loops
Similar to the construction of `if let`, the `while let` conditional loop allows a `while` loop to run for as long as a pattern continues to match.
We first saw this in Ch17, where we used it to keep looping as long as a stream produced new values.
Similarly here we show a `while let` loop that waits on messages sent between threads, but in this case checking a `Result` instead of an `Option`.
```rust
let (tx, rx) = std::sync::mpsc::channel();
std::thread::spawn(move || {
for val in [1, 2, 3] {
tx.send(val).unwrap();
}
});
while let Ok(value) = rx.recv() {
println!("{value}");
}
```
This example will print 1, 2, and 3.
When we saw `recv` back in Ch16, we unwrapped the error directly, or interacted with it as an iterator using a `for` loop.
Here shows we can also use `while let`, because the `recv` method returns `Ok` as long as the sender is producing messages and then produces an `Err` once the sender side disconnects.
## `for` Loops
In a `for` loop, the value that directly follows the keyword `for` is a pattern.
This example demonstrates how to use a pattern in a `for` loop to destructure or break apart, a type as part of the `for` loop.
```rust
let v = vec!['a', 'b', 'c'];
for (index, value) in v.iter().enumerate() {
println!("{value} is at index {index}");
}
```
Output
```rust
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.52s
Running `target/debug/patterns`
a is at index 0
b is at index 1
c is at index 2
```
We adapt an iterator using the `enumerate` method so it produces a values and the index for that value, placed into a tuple.
The first value produced is the tuple `(0, 'a')`.
When this value is matched to the patter `(index, value)`, `index` will be `0` and `value` will be `'a'`, printing the first line out the output.
## `let` Statements
Prior to this ch, we only discussed using patterns with `match` and `if let`, but in fact, we have used patterns in other places as well.
This includes `let` statements.
For example consider this straightforward variable assignment with `let`
```rust
let x = 5;
```
Every time you used a `let` statement like this you have been using patterns, although you might not have realized it.
More formally, a `let` statement looks like this
```
let PATTERN = EXPRESSION;
```
In statements like `let x = 5;` with a variable name in the `PATTERN` slot.
The variable name is just a particularly simple form of a pattern.
Rust compares the expression against the pattern and assign any names it finds.
So in the `let x = 5;` example `x` is a pattern that means "bind what matches here to the variable `x`."
Because the name `x` is the whole pattern, this pattern effectively means "bind everything to the variable `x`, whatever the values is."
To see the pattern matching aspect of `let` more clearly, consider this, which uses a pattern with `let` to destructure a tuple.
```rust
let (x, y, z) = (1, 2, 3);
```
Here we match a tuple against a pattern.
Rust compares the value `(1, 2, 3)` to the pattern `(x, y, z)` and sees that the value matches the pattern.
Rust binds `1` to `x`, `2` to `y`, and `3` to `z`.
You can think of this tuple pattern as nesting three individual variable patterns inside it.
If the number of elements in the pattern doesn't match the number of elements in the tuple, the overall type won't match and we will get a compiler error.
Here shows an attempt to destructure a tuple with three elements into two variables, this will not work.
```rust
let (x, y) = (1, 2, 3);
```
Here is the compiler error form attempting to compile
```
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
error[E0308]: mismatched types
--> src/main.rs:2:9
|
2 | let (x, y) = (1, 2, 3);
| ^^^^^^ --------- this expression has type `({integer}, {integer}, {integer})`
| |
| expected a tuple with 3 elements, found one with 2 elements
|
= note: expected tuple `({integer}, {integer}, {integer})`
found tuple `(_, _)`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `patterns` (bin "patterns") due to 1 previous error
```
In order to fix this error, we could ignore one or more of the values in the tuple using `_` or `..`
You will see this in the ["Ignoring Values in a Pattern"]()
If the problem is that we have too many variables in the pattern, the solution is to make the types match by removing variables so the number equals the number of elements in the tuple.
## Function Parameters
Function parameter can also be patterns.
The code here, which declares a function named `foo` that takes one parameter named `x` of type `i32`, should by now look familiar.
```rust
fn foo(x: i32) {
// code goes here
}
```
The `x` part is a pattern.
As we did with `let` we could match a tuple in a function's arguments to the pattern.
In this next example, this splits the values in a tuple as we pass it to a function.
```rust
fn print_coordinates(&(x, y): &(i32, i32)) {
println!("Current location: ({x}, {y})");
}
fn main() {
let point = (3, 5);
print_coordinates(&point);
}
```
This code prints `Current loaction: (3, 5)`.
The values `&(3, 5)` match the pattern `&(x, y)`, so `x` is the value `3` and `y` is the value `5`.
We can also use patterns in closure parameter lists in the same way as in function parameter lists, because closure are similar to functions (discussed in Ch 13).
Now we have seen several ways of using patterns, but patterns don't work the same in every place we can use them.
In some places, the patterns must be irrefutable; other circumstances, they can be refutable.
This will be discussed in the next section [Here](./Refutability.md)

107
Refutability.md Normal file
View File

@ -0,0 +1,107 @@
# Refutability: Whether a Pattern Might Fail to Match
Patterns come in two forms:
- Refutable
- Irrefutable
Patterns that will match for any possible value passed are *irrefutable*.
An example would be `x` in the statement `let x = 5;` because `x` matches anything and therefore cannot fail to match.
Patterns that can fail to match for some possible value are *refutable*.
An example would be `Some(x)` in the expression `if let Some(x) = a_value` because if the value in the `a_value` variable is `None` rather than `Some`, the `Some(x)` pattern will not match.
Function parameters, `let` statements and `for` loops can only accept irrefutable patterns, because the program cannot do anything meaningful when values don't match.
The `if let` and `while let` expressions and the `let`-`else` statement accept refutable and irrefutable patterns, but the compiler warns against irrefutable patterns.
This is because by definition they are intended to handle possible failure.
The functionality of a conditional is in its ability to perform differently depending on success or failure.
Generally you shouldn't have to worry about the distinction between refutable and irrefutable patterns.
However you do need to be familiar with the concept of refutability so you can respond when you see it in an error message.
In these cases, you will need to change either the pattern or the construct you are using the pattern with, depending on the intended behavior of the code.
Now lets take a look at an example of what happens when you try to use a refutable pattern where Rust requires an irrefutable pattern and vice versa.
Here shows a `let` statement, but for the pattern we have specified `Some(x)`, a refutable pattern.
As expected, this code will not compile.
```rust
let Some(x) = some_option_value;
```
If `some_option_value` was a `None` value, it would fail to match the pattern `Some(x)`, meaning the pattern is refutable.
However, the `let` statement can only accept an irrefutable pattern because there is nothing valid the code can do with a `None` value.
At compile time, Rust will complain that we have tried to use a refutable pattern where an irrefutable pattern is required
```
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
error[E0005]: refutable pattern in local binding
--> src/main.rs:3:9
|
3 | let Some(x) = some_option_value;
| ^^^^^^^ pattern `None` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `Option<i32>`
help: you might want to use `let else` to handle the variant that isn't matched
|
3 | let Some(x) = some_option_value else { todo!() };
| ++++++++++++++++
For more information about this error, try `rustc --explain E0005`.
error: could not compile `patterns` (bin "patterns") due to 1 previous error
```
Because we didn't cover (and couldn't cover) every valid value with the pattern `Some(x)`, Rust rightfully produces a compiler error.
If we have a refutable pattern where an irrefutable pattern is needed, we can fix it by changing the code that uses the pattern.
Instead of using `let`, we can use `if let`.
Then if the code doesn't match, the code will just skip the code in the curly brackets, giving a way to continue validly.
Here shows a fix to the code
```rust
if let Some(x) = some_option_value {
println!("{x}");
}
```
We given the code an out, this code is perfectly valid now.
However, if we give `if let` an irrefutable pattern, such as `x`, the compiler will give a warning.
```rust
if let x = 5 {
println!("{x}");
};
```
Rust complains that it doesn't make sense to use `if let` with an irrefutable pattern
```
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
warning: irrefutable `if let` pattern
--> src/main.rs:2:8
|
2 | if let x = 5 {
| ^^^^^^^^^
|
= note: this pattern will always match, so the `if let` is useless
= help: consider replacing the `if let` with a `let`
= note: `#[warn(irrefutable_let_patterns)]` on by default
warning: `patterns` (bin "patterns") generated 1 warning
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.39s
Running `target/debug/patterns`
5
```
For this reason, match arms must use refutable patterns, except for the last arm, which should match any remaining values with an irrefutable pattern.
Rust allows us to use an irrefutable pattern in a `match` with only one arm.
This syntax isn't particularly useful and could be replaced with a simpler `let` statement.
Next we will cover all the syntax we can use to create patterns [here](./Pattern%20Syntax.md)

View File

@ -0,0 +1,254 @@
# Using Trait Objects That Allow for Values of Different Types
In ch8 we discussed one of the limitation of vectors is that they can store elements of only one type
We created a workaround where we defined a `SpreadsheetCell` enum that had variants to hold integers, floats and text.
This meant that we could store different types of data in each cell and still have a vector that represented a row of cells.
This is a good solution when our interchangeable items are a fixed set of types that we know when our code is compiled.
However, sometimes we want our library user to be able to extend the set of types that are valid in a particular situation.
To show how we may achieve this, we will create a example graphical user interface (GUI) tool that iterates through a list of items, calling a `draw` method on each one to draw it to the screen.
This is a common technique for GUI tools.
We will start with creating a library crate called `gui` that contains the structure of a GUI library.
This crate might include some types for people to use, such as `Button` or `TextField`.
In addition `gui` users will want to create their own types that can be drawn.
For example, one programmer might add an `Image` and another programmer might add a `SelectBox`
In this example we won't build a fully fledged GUI library, but instead will show how all of the pieces would fit together.
At the time of writing the library, we cant know and define all the types other programmers might want to create.
We do know that `gui` needs to keep track of many values of different and it needs to call a `draw` method on each of these differently typed values.
It doesn't need to know exactly what will happen when we call the `draw` method, just that the value will have that method available for us to call.
In a language to do this, we might define a class named `Component` that has a method named `draw` on it.
The other classes, such as `Button`, `Image` and `SelectBox`, would inherit form `Component` and thus inherit the `draw` method.
Each one would override the `draw` method to define their custom behavior, but the framework could treat all of the types as if they were `Component` instances and call `draw` on them.
Due to Rust not having inheritance, we need a different way to structure the `gui` library to allow users to extend it with new types.
## Defining a Trait for Common Behavior
In order to implement the behavior we want `gui` to have, we will define a trait named `Draw` that will have one method named `draw`.
We then can define a vector that takes a *trait object*.
A trait object points to both an instance of a type implementing our specified trait and a table used to look up trait methods on that type at runtime.
We create a trait object by specifying some sort of pointer, such as a `&` reference or a `Box<T>` smart pointer, then the `dyn` keyword and then specifying the relevant trait.
We will discuss about the reason trait objects must use a pointer in Ch20.
We can use trait objects in place of a generic or concrete type.
Whenever we use a trait object, Rust's type system will ensure at compile time that any value used in that context will implement the trait object's trait.
Due to this we don't need to know all possible types at compile time.
We mentioned that in Rust, we refrain from calling structs an enums "objects" to distinguish them from other language's objects.
In a struct or enum, the data in the struct fields and the behavior in `impl` blocks are separated, where as in other languages, the data and behavior combined into one concept is often labeled an object.
Trait objects *are* more like objects in other languages in the sense that they combine data and behavior.
Trait objects still differ form traditional objects in that we can't add data to a trait object.
Trait objects aren't as generally useful as objects in other languages: their purpose is to allow abstraction across common behavior.
Here is an example of how to define a trait named `Draw` with one method named `draw`
```rust
pub trait Draw {
fn draw(&self);
}
```
This is similar syntax to how we defined traits in Ch10.
Next comes some new syntax.
Here we define a struct named `Screen` that holds a vector named `components`.
This vector is of type `Box<dyn Draw>`, which is a trait object; it is a stand in for any type inside a `Box` that implements the `Draw` trait.
```rust
pub struct Screen {
pub components: Vec<Box<dyn Draw>>,
}
```
Now on the `Screen` struct we will define a method named `run` that will call the `draw` method on each of its `components`
```rust
impl Screen {
pub fn run(&self) {
for component in self.components.iter() {
component.draw();
}
}
}
```
This works differently form defining a struct that uses a generic type parameter with trait bounds.
A generic type parameter can only be substituted with one concrete type at a time, whereas trait objects allow for multiple concrete types to fill in for the trait object at runtime.
For example we could have defined the `Screen` struct using generic type and a trait bound, this is shown here.
```rust
pub struct Screen<T: Draw> {
pub components: Vec<T>,
}
impl<T> Screen<T>
where
T: Draw,
{
pub fn run(&self) {
for component in self.components.iter() {
component.draw();
}
}
}
```
This restricts us to a `Screen` instance that has a list components all of type `Button` or all of type `TextField`.
If you only ever have homogeneous collections, using generics and trait bounds is preferable because the definitions will be monomerized at compile time to use the concrete types.
With the method using trait objects, one `Screen` instance can hold a `Vec<T>` that contains a `Box<Button>` as well as a `Box<TextField>`.
Now lets look at how that works and then we will talk about the runtime performance implications.
## Implementing the Trait
Next we will add some types that implement the `Draw` trait.
We will provide the `Button` type.
So the `draw` method won't have any useful implementation in its body.
To imagine what the implementation might look like, a `Button` struct might have fields for `width`, `height` and `label`.
Here is an example of this
```rust
pub struct Button {
pub width: u32,
pub height: u32,
pub label: String,
}
impl Draw for Button {
fn draw(&self) {
// code to actually draw a button
}
}
```
The `width`, `height` and `label` fields on `Button` will differ from the fields on other components.
For example a `TextField` type might have those same fields plus a `placeholder` field.
Each of the types we want to draw on the screen will implement the `Draw` trait, but will use different code in the `draw` method to define how to draw that particular type as `Button` has here (without any actual GUI code).
The `Button` type, for instance, might have an additional `impl` block containing method related to what happens when a user clicks the button.
These kinds of methods related to what happens when a user clicks the button.
These kinds of methods won't apply to types like `TextField`.
If someone using our library decides to implement a `SelectBox` struct that has `width`, `height`, and `options` fields, they implement the `Draw` trait on the `SelectBox` type as well.
This is shown below
```rust
use gui::Draw;
struct SelectBox {
width: u32,
height: u32,
options: Vec<String>,
}
impl Draw for SelectBox {
fn draw(&self) {
// code to actually draw a select box
}
}
```
When we originally wrote the library, we didn't know that someone might add the `SelectBox` type, but our `Screen` implementation was able to operate on the new type and draw it because `SelectBox` implements the `Draw` trait.
This means that it implements the `draw` method.
This concept of being concerned only with the messages a value responds to rather than the value's concrete type.
This is similar to the concept of *duck typing* in dynamically typed languages.
If it walks like a duck and quacks like a duck, then it must be a duck!
In the implementation of `Run` on `Screen`, `run` doesn't need to know what the concrete type of each component is.
It doesn't check whether a component is an instance of a `Button` or a `SelectBox`, it just calls the `draw` method on the component.
By specifying `Box<dyn Draw>` as the type of the values in the `componets` vector.
Here we have defined `Screen` to need values that we can call the `draw` method on.
The advantage of using trait objects and Rust's type system to write code similar to code using duck typing is that we never have to check whether a value implements a particular method at runtime or worry about getting errors if a value doesn't implement a method but we call it anyway.
Rust will not compile the code if the values don't implement the traits that the trait objects need.
Here is an example of this shows what happens if we try to create a `Screen` with a `String` as a component
```rust
use gui::Screen;
fn main() {
let screen = Screen {
components: vec![Box::new(String::from("Hi"))],
};
screen.run();
}
```
Here we will get this error because `String` doesn't implement the `Draw` trait
```
$ cargo run
Compiling gui v0.1.0 (file:///projects/gui)
error[E0277]: the trait bound `String: Draw` is not satisfied
--> src/main.rs:5:26
|
5 | components: vec![Box::new(String::from("Hi"))],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Draw` is not implemented for `String`
|
= help: the trait `Draw` is implemented for `Button`
= note: required for the cast from `Box<String>` to `Box<dyn Draw>`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `gui` (bin "gui") due to 1 previous error
```
This error let us know that either we are passing something to `Screen` we didn't mean to pass and so should pass a different type or we should implement `Draw` on `String` so that `Screen` is able to call `draw` on it.
## Trait Objects Preform Dynamic Dispatch
Recall the ["Performance of Code Using Generics"](./Generics.md#perfomance-of-code-using-generics) our discussion on the monomorphization process performed on generics by the compiler.
The compiler generates nongeneric implementations of functions and methods for each concrete type that we use in place of a generic type parameter.
The code that results from monomorphization is doing *static dispatch*, which is when the compiler know what method you are calling at compile time.
This is the opposite to *dynamic dispatch*, which is when the compiler can't tell at compile time which method you are calling.
In dynamic dispatch cases, the compiler emits code that at runtime will figure out which method to call.
When we use trait objects, Rust must use dynamic dispatch.
The compiler won't know all the types that might be used with the code that is using trait objects, so it doesn't know all the types that might be used with the code that is using trait objects, so it doesn't know which method implemented on which type to call.
Instead at runtime, Rust uses the pointers inside the trait object to know which method to call.
This lookup incurs a runtime cost that doesn't occur with static dispatch.
Dynamic dispatch also prevents the compiler from choosing to inline a method's code, which prevents some optimizations, and Rust has some rules about where you can and cannot use dynamic dispatch.
This is called [dyn compatibility](https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility).
However you will get the extra flexibility in the code that we wrote before and we were able to support in the following examples, so it is a trade-off to consider.

View File

@ -201,3 +201,205 @@ This was in terms of `Unpin`, not `Pin`.
How does `Pin` relate to `Unpin` and why does `Future` need `self` to be in a `Pin` type to call `poll`?
Remember from before, a series of await points in a future get compiled into a state machine, and the compiler makes sure that state machine follows all of Rust's normal rules around safety, which includes borrowing and ownership.
In order to make this work, Rust looks at what data is needed between one await point and either the next await point or the end of the async block.
Each variant get the access it needs to the data that will be used in that section of the source code, whether by taking ownership of that data or by getting a mutable or immutable reference to it.
If we get anything wrong about the ownership or references in a given async block, the borrow checker will tell us.
When we want to move around the future that corresponds to that block, like moving it into a `Vec` to pass to `join_all`, where things get tricker.
When we move a future, either by pushing it into a data structure to use as an iterator with `join_all` or by returning from a function, this actually means moving the state machine Rust creates for us.
Unlike most other types in Rust, the future Rust creates for async blocks can end up with references to themselves in the fields of any given variant.
This is shown in this illustration
<img src="https://doc.rust-lang.org/book/img/trpl17-04.svg" />
By default, any object that has a reference to itself is unsafe to move, because references always point to the actual memory address of whatever they refer to.
If you move the data structure itself, those internal references will be left pointing to the old location.
However that memory location is now invalid.
One thing is that its value will not be updated when you make changes to the data structure.
Another thing, which is more important, is the computer is now free to reuse that memory for other purposes.
You could end up reading completely unrelated data later.
<img src="https://doc.rust-lang.org/book/img/trpl17-05.svg" />
Theoretically, the Rust compiler could try to update every reference to an object whenever it gets moved, but that could add a lot of performance overhead.
This is especially true if a whole web of references needs updating.
If we could instead ensure that the data structure *doesn't move in memory*, we then wouldn't have to update any references.
This is exactly what Rust's borrow checker requires: in safe code, it prevents you from moving any item with an active reference to it.
`Pin` builds on that give us the exact guarantee we need.
When we *pin* a value by wrapping a pointer to that value in `Pin`, it can no longer move.
Thus if you have `Pin<Box<SomeType>>`, you actually pin the `SomeType` value, *not* the `Box` pointer.
The image illustrates this process.
<img src="https://doc.rust-lang.org/book/img/trpl17-06.svg" />
In fact, the `Box` pointer can still move around freely.
We car about making sure the data ultimately being referenced stays in place.
If a pointer moves around, *but the data it points is in the same place*, there is no potential problem.
As an independent exercise, look at the dos for the types as well as the `std::pin` module and try to work out how you would do do this with a `Pin` wrapping a `Box`.
The key is that the self-referential type cannot move, because it is still pinned.
<img src="https://doc.rust-lang.org/book/img/trpl17-07.svg" />
However most types are perfectly safe to move around, even if they happen to be behind a `Pin` pointer.
We only need to think about pinning when the items have internal references.
Primitives values such as numbers and Booleans are safe since they obviously don't have any internal references, so they are obviously safe.
Neither do most types you normally work with in Rust.
You can move around a `Vec`, for example, without worrying.
given what we have seen, if you have a `Pin<Vec<String>>`, you would have to everything via the safe but restrictive APIs provided by `Pin`/
Even though a `Vec<String>` is always safe to move if there are no other references to it.
We need a way to tell the compiler that it is fine to move items around in cases like this, this is where `Unpin` comes into action.
`Unpin` is a marker trait, similar to the `Send` and `Sync` traits.
Thus has no functionality of its own.
Marker traits exist only to tell the compiler to use the type implementing a given trait in a particular context.
`Unpin` informs the compiler that a given type does *not* need to uphold any guarantees about whether the value in question can be safely moved.
Just like `Send` and `Sync`, the compiler implements `Unpin` automatically for all types where it can prove it is safe.
A special case, is where `Unpin` is *not* implemented for a type.
The notation for this is `impl !Unpin for *SomeType*`, where `*SomeType*` is the name of a type that *does* need to uphold those guarantees to be safe whenever a pointer to that type is used in a `Pin`.
The relationship between `Pin` and `Unpin` has two important things to remember:
- `Unpin` is the "normal case", `!Unpin` is the special case
- Whether a type implements `Unpin` or `!Unpin` *only* matters when you are using a pinned pointer to that type like `Pin<&mut *SomeType*>`
To make that concrete, think about a `String`: it has a length and the Unicode characters that make it up.
We can wrap a `String` in `Pin`.
However `String` automatically implements `Unpin` as do most other types in Rust.
<img src="https://doc.rust-lang.org/book/img/trpl17-08.svg" />
Pinning a `String`; the dotted line indicates that the `String` implements the `Unpin` trait, and thus is not pinned.
This results, in the ability to do things that would be illegal if `String` implemented `!Unpin`, such as replacing one string with another at the exact same location in has no interval references that make it unsafe to move around.
This wouldn't violate the `Pin` contract, because `String` has no internal references that make it unsafe to move around.
This is precisely why it implements `Unpin` rather than `!Unpin`.
<img src="https://doc.rust-lang.org/book/img/trpl17-09.svg" />
Now that we know enough to understand the errors reported for that `join_all` call from before.
There we originally tried to move the futures produced by the async blocks into a `Vec<Box<dyn Future<Output = ()>>>`.
As we have seen, those futures may have internal references, so they don't implement `Unpin`.
They need to be pinned and then we can pass the `Pin` type into the `Vec`, confident that the underlying data in the futures will *not* be moved.
`Pin` and `Unpin` are mostly important for building lower-level libraries, or when you are building a runtime itself, rather than for day-to-day Rust.
When you see these traits in error messages, now you will have a better idea of how to fix your code.
Note, the combination of `Pin` and `Unpin` makes it possible to safely implement a whole class of complex types in Rust that would otherwise prove challenging because they are self-referential.
Types that require `Pin` show up most commonly in async Rust today.
Every once in a while, you may see them in other contexts too.
The specifics of how `Pin` and `Unpin` work, and the rules they are required to uphold are covered extensively in the `API` documentation for `std::pin`, so you can check there for more info.
In fact there is a whole BOOK on async Rust programming, that you can find [here](https://rust-lang.github.io/async-book/)
## The `Stream` Trait
As we leaned earlier, streams are similar to asynchronous iterators.
Unlike `Iterator` and `Future`, `Stream` has no definition in the std library (as of writing this), but there *is* a very common definition form the `fuitures` crate used throughout the ecosystem.
Here is a review of the `Iterator` and `Future` traits before going into how a `Stream` trait might merge them together.
From `Iterator`, we have the idea of a sequence: its `next` method provides an `Option<Self::Item>`
From `Future`, we have the idea of readiness over time: the `poll` method provides a `Poll<Self::Output>`
This allows us to represent a sequence of items that become ready over time, we define a `Stream` trait that puts those features together.
```rust
use std::pin::Pin;
use std::task::{Context, Poll};
trait Stream {
type Item;
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>
) -> Poll<Option<Self::Item>>;
}
```
Here the `Stream` trait defines an associated type called `Item` for the type of the items produced by stream.
This is similar to `Iterator`, where there may be zero to many items, and unlike `Future`, where there is always a single `Output`, even if it is the unit type `()`.
`Stream` also defines a method to get those items.
We call it `poll_next`, to make it clear that it polls in the same way `Future::poll` does and produces a sequence of items in the same way `Iterator::next` does.
Its return type combines `Poll` with `Option`.
The outer type is `Poll`, because it has to be checked for readiness, just as a future does.
The inner type is `Option`, because it needs to signal whether there are more messages, just as an iterator does.
Somethin like this will likely end up as part of Rust's standard library.
In the meantime, it is part of the toolkit of most runtimes, so you can rely on it, and everything that will be covered should apply generally.
In the example we saw previously in the section on streaming, we didn't use `Poll_next` or `Stream`, but instead used `next` and `StreamExt`.
We *could* work with futures directly via their `poll` method.
Using `await` is much nicer, and the `StreamExt` trait supplies the `next` method so we can do just this:
```rust
trait StreamExt: Stream {
async fn next(&mut self) -> Option<Self::Item>
where
Self: Unpin;
// other methods...
}
```
Note: The definition that we used earlier in the ch looks slightly different that this.
This is because it supports versions of Rust that did not yet support using async functions in traits.
As a result it looks like this:
```rust
fn next(&mut self) -> Next<'_, Self> where Self: Unpin;
```
This `Next` type is a `struct` that implements `Future` and allows us to name the lifetime of the reference to `self` with `Next<'_, Self>`, so that `await` can work with this method.
The `StreamExt` trait also has some interesting method available to use with steams.
`StreamExt` is automatically implemented for every type that implements `Stream`.
These traits are defined separately to enable the community to iterate on convenience APIs without affecting the foundational trait.
In the version of `StreamExt` used in the `trpl` crate, the trait not only defines the `next` method but also supplies a default implementation of `next` that correctly handles the details of calling `Stream::poll_next`.
Meaning that even when you need to write your own streaming data type, you *only* have to implement `Stream` and then anyone who uses your data type can use `StreamExt` and its methods with it automatically.

585
Unsafe Rust.md Normal file
View File

@ -0,0 +1,585 @@
# Unsafe Rust
So far the code we have discussed has had Rust's memory safety guarantees enforced at compile time.
Rust has a second language hidden inside it that doesn't enforce memory safety guarantees.
This is called *unsafety Rust*, which works just like regular Rust but it gives extra superpowers.
Unsafe Rusts exists because static analysis is conservative.
When the compiler tries to determine whether or not code upholds the guarantees, it is better for it to reject some valid programs than to accept some invalid programs.
Even if the code *may* be ok, if the compiler doesn't have enough information to be confident and therefore reject the code.
In these cases you can use unsafe code to tell the compiler, "Trust me, I know what I'm doing."
Be warned that you use unsafe Rust at your own risk.
If you use unsafe code incorrectly, problems can occur due to memory unsafety, such as null pointer dereferencing.
Rust has an unsafe alter ego is that the underlying computer hardware is inherently unsafe.
If Rust didn't allow us to do unsafe operations, you couldn't do certain tasks.
Rust needs to allow you to do low-level systems programming, such as directly interacting with the operating system or even writing your own operating system.
Working with low-level systems programming is one of the goals of the language.
## Unsafe Superpowers
To switch to unsafe Rust, you need to use the `unsafe` keyword and then start a new block that holds the unsafe code.
You can do five additional actions in unsafe Rust that you can't do in safe Rust, which we call *unsafe superpowers*.
These superpowers are:
- Dereference a raw pointer
- Call an unsafe function or method
- Access or modify a mutable static variable
- Implement an unsafe trait
- Access fields of a `union`
Note: `unsafe` does not turn off the borrow checker or disable any other of Rust's safety checks.
If you use a reference in unsafe code, it will still be checked.
The `unsafe` keyword only gives access to these five features that are then not checked by the compiler for memory safety.
You will still get some degree of safety inside of an unsafe block.
Additionally `unsafe` does not mean the code inside the block is necessarily dangerous or that it will definitely have memory safety problems.
The intent as the programmer, you will ensure the code inside an `unsafe` block will access memory in a valid way.
People are fallible, and mistakes will happen, but by requiring these five unsafe operations to be inside blocks annotated with `unsafe` you will know that any errors related to memory safety must be within an `unsafe` block.
Keep `unsafe` blocks small: you will be thankful later when you investigate memory bugs.
To isolate unsafe code as much as possible, it is best to enclose unsafe code within a safe abstraction and provide a safe API (This will be covered when we examine unsafe functions and methods).
Parts of the std library are implemented as safe abstractions over unsafe code that has been audited.
Wrapping unsafe code in a safe abstraction prevents uses of `unsafe` from leaking out into all the places that you want to use the functionality implemented with `unsafe` code, because using aa safe abstraction is safe.
Now we will look into each of the five unsafe superpowers.
We will also look at some abstractions that provide a safe interface to unsafe code.
## Deferencing a Raw Pointer
We mentioned before that the compiler ensures references are always valid.
Unsafe Rust has two new types called *raw pointers* that are similar to references
Raw pointers can be immutable or mutable, just like with references, are written as `*const T` and `*mut T`, respectively.
The asterisk isn't the dereference operator, it is part of the type name.
In the context of raw pointers, *immutable* means that the pointer can't be directly assigned to after being dereferenced.
Different from references and smart pointers, raw pointers:
- Are allowed to ignore the borrowing rules by having both immutable and mutable pointers or multiple mutable pointers to the same location
- Aren't guaranteed to point to valid memory
- Are allowed to be null
- Don't implement nay automatic cleanup
By opting out of Rust's enforced guarantees, you can give up safety in exchange for greater performance or the ability to interface with another language or hardware where Rust's guarantees don't apply.
Here is an example of how to create an immutable and a mutable raw pointer.
```rust
let mut num = 5;
let r1 = &raw const num;
let r2 = &raw mut num;
```
Note that we don't include the `unsafe` keyword here.
We can create raw pointers in safe code; we just can't dereference raw pointers outside an unsafe block (We will see this later).
We have created raw pointers by using the raw borrow operators.
`&raw const num` creates a `*const i32` immutable raw pointer.
`&raw mut num` creates a `*mut i32` mutable raw pointer.
Because we created them directly form a local variable, we know these particular raw pointers are valid, but we can't make that assumption about just any raw pointer.
In order to demonstrate this, we will create a raw pointer whose validity we can't be so certain of, using `as` to cast a value instead of using the raw reference operators.
This shows how to create a raw pointer to an arbitrary location in memory.
Trying to use arbitrary memory is undefined: there might be data at that address or there might not, the compiler might optimize the code so there is no memory access, or the program might error with a segmentation fault.
Usually there is no good reason to write code like this, especially in cases where you can use a raw borrow operator instead, but it is possible.
```rust
let address = 0x012345usize;
let r = address as *const i32;
```
Remember that we can create raw pointers in safe code, but we can't *dereference* raw pointers and read the data being pointed to.
Here we use the dereference operator `*` on a raw pointer that requires an `unsafe` block.
```rust
let mut num = 5;
let r1 = &raw const num;
let r2 = &raw mut num;
unsafe {
println!("r1 is: {}", *r1);
println!("r2 is: {}", *r2);
}
```
Creating a pointer does no hard. It is only when we attempt to access the value that it points at that we might end up dealing with an invalid value.
Note in the first and third example, we created `*const i32` and `*mut i32` raw pointers that both pointed to the same memory location where we `num` is stored.
If we instead tried to create an immutable and a mutable reference to `num`, the code would not have compiled because Rust's ownership rules don't allow a mutable reference at the same time as any immutable references.
With raw pointers, we can create a mutable pointer and an immutable pointer to the same location and change data through the mutable pointer, potentially create a data race.
With all of the dangers, why ever use raw pointers?
Once major use case is when interfacing with C code, as you will see in the next section ["Calling an Unsafe Function or Method"]().
Another case is when building up safe abstractions that the borrow checker doesn't understand.
We will introduce unsafe function and then look at an example of a safe abstraction that uses unsafe code.
## Calling an Unsafe Function or Method
The second type of superpower that you can perform in an unsafe block is calling unsafe functions.
Unsafe functions and methods look exactly like regular functions and methods, but they have an extra `unsafe` before the rest of the definitions.
The `unsafe` keyword indicates the function has requirements we need to uphold when we call this function, because Rust can't guarantee we have met these requirements.
By calling an unsafe function within an `unsafe` block, we are saying that we have read this function's documentation and take responsibility for upholding the function's contracts.
This code is an unsafe function named `dangerous` that doesn't do anything in its body
```rust
unsafe fn dangerous() {}
unsafe {
dangerous();
}
```
We must call the `dangerous` function within a separate `unsafe` block.
If we attempted to call `dangerous` without the `unsafe` block, we would get this error
```
$ cargo run
Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example)
error[E0133]: call to unsafe function `dangerous` is unsafe and requires unsafe function or block
--> src/main.rs:4:5
|
4 | dangerous();
| ^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
For more information about this error, try `rustc --explain E0133`.
error: could not compile `unsafe-example` (bin "unsafe-example") due to 1 previous error
```
With the `unsafe` block, we are asserting to Rust that we have read this function's documentation, we understand how to use it properly, and we have verified that we are fulfilling the contract of the function.
To perform unsafe operations in the body of an unsafe function you still need to use an `unsafe` block just as within a regular function, and the compiler will warn you if you forget.
This helps to keep `unsafe` blocks as small as possible, as unsafe operations may not be needed across the whole function body.
### Creating a Safe Abstraction over Unsafe Code
Just because a function contains unsafe code, this does mean we need to mark the entire function as unsafe.
In fact wrapping unsafe is a common abstraction.
For example, let's take a look at the `split_at_mut` function from the std library, which requires some unsafe code.
We will also explore how we might implement it.
This safe method is defined on mutable slices: it takes once slice and makes it two by splitting the slice at the index given as an argument.
Here is how to use `split_at_mut`
```rust
let mut v = vec![1, 2, 3, 4, 5, 6];
let r = &mut v[..];
let (a, b) = r.split_at_mut(3);
assert_eq!(a, &mut [1, 2, 3]);
assert_eq!(b, &mut [4, 5, 6]);
```
We can't implement this function using only safe Rust.
An attempt might look something like this, which will not compile.
For simplicity we will implement `split_at_mut` as a function rather than a method and only for slices of `i32` values rather than for a generic type `T`.
```rust
fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
let len = values.len();
assert!(mid <= len);
(&mut values[..mid], &mut values[mid..])
}
```
This function first gets the total length of the slice.
Then it asserts that the index given as a parameter is within the slice by checking whether it is less than or equal to the length.
This assertion means that if we pass an index that is greater than the length to split the slice at, the function will panic before it attempts to use that index.
Next we return two mutable slices in a tuple, one form the start of the original slice to the `mid` index and another from `mid` to the end of the slice.
We get this compilation error
```
$ cargo run
Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example)
error[E0499]: cannot borrow `*values` as mutable more than once at a time
--> src/main.rs:6:31
|
1 | fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
| - let's call the lifetime of this reference `'1`
...
6 | (&mut values[..mid], &mut values[mid..])
| --------------------------^^^^^^--------
| | | |
| | | second mutable borrow occurs here
| | first mutable borrow occurs here
| returning this value requires that `*values` is borrowed for `'1`
|
= help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
For more information about this error, try `rustc --explain E0499`.
error: could not compile `unsafe-example` (bin "unsafe-example") due to 1 previous error
```
Rust's borrow checker can't understand that we are borrowing different parts of the slice.
It only knows that we are borrowing from the same slice twice.
Borrowing different parts of a slice fundamentally ok because the two slices aren't overlapping, but Rust isn't smart enough to know this.
When we know code is ok, but Rust doesn't, it is time to reach for unsafe code.
Below shows how to use an `unsafe` block, a raw pointer, and some calls to unsafe functions to make the implementation of `split_at_work`.
```rust
use std::slice;
fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
let len = values.len();
let ptr = values.as_mut_ptr();
assert!(mid <= len);
unsafe {
(
slice::from_raw_parts_mut(ptr, mid),
slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)
}
}
```
Remember from ["The Slice Type"](), from Ch4 that slices are a pointer to some data and the length of the slice.
We can use the `len` method to get the length of a slice and the `as_mut_ptr` method to access the raw pointer of a slice.
In this case because we have a mutable slice to `i32` values, `as_mut_ptr` returns a raw pointer with the type `*mut i32`, which we have stored in the variable `ptr`.
We keep the assertion that the `mid` index is within the slice.
Next we get to the unsafe code: the `slice::from_raw_parts_mut` function takes a raw pointer and a length, and it creates a slice.
We use this function to create a slice that starts from `ptr` and is `mid` items long.
Next we call the `add` method on `ptr` with `mid` as an argument to get a raw pointer that starts at `mid`, and we create a slice using that pointer and the remaining number of items after `mid` as the length.
The function `slice::from_raw_parts_mut` is unsafe because it takes a raw pointer and must trust that this pointer is valid.
The `add` method on raw pointers is also unsafe, because it must trust that the offset location is also a valid pointer.
We have to put this in an `unsafe` block around our calls to `slice::from_raw_parts_mut` and `add` so we could call them.
By looking at the code and by adding the assertion that `mid` must be less than or equal to `len`.
We can tell that all the raw pointers used within the `unsafe` block will be valid pointers to data within the slice.
This is an acceptable and appropriate use of `unsafe`.
Notice that we don't need to mark the resulting `split_at_mut` function as `unsafe`.
We can call this function form safe Rust.
We have created a safe abstraction to the unsafe code with an implementation of the function that uses `unsafe` code in a safe way, because it creates only valid pointers from the data this function has access to.
By contrast, the use of `slice::from_raw_parts_mut` here would likely crash when the slice is used.
This code takes an arbitrary memory location and creates a slice 10,000 items long.
```rust
use std::slice;
let address = 0x01234usize;
let r = address as *mut i32;
let values: &[i32] = unsafe { slice::from_raw_parts_mut(r, 10000) };
```
We don't own the memory at this arbitrary location and there is no guarantee that the slice this code creates contains valid `i32` values.
Attempting to use `values` as though it's aa valid slice results in undefined behavior.
## Using `extern` Functions to Call External Code
Sometimes, your Rust code might need to interact with code written in another language.
To enable this, Rust has the keyword `extern` that facilitates the creation and use of a *Foreign Function Interface (FFI)*.
An FFI is a way for a programming language to defined functions and enable a different (foreign) programming language to call those functions.
This code demonstrates how to set up an integration with the `abs` function form the C std library.
Functions declared within `extern` blocks are usually unsafe to call from Rust code, so they must also be marked `unsafe`.
The reason is that other languages don't enforce Rust's rules and guarantees, and Rust can't check them, so the responsibility falls on the programmer to ensure safety.
```rust
unsafe extern "C" {
fn abs(input: i32) -> i32;
}
fn main() {
unsafe {
println!("Absolute value of -3 according to C: {}", abs(-3));
}
}
```
Within the `unsafe extern "C"` block, we list the names and signatures of external functions from another language we want to call.
The `"C"` part defines which *application binary interface (ABI)* the external function uses: the ABI defines how to call the function at the assembly level.
The `"C"` ABI is the most common and follows the C programming language's ABI.
This particular function does not have any memory safety considerations.
In fact, we know that any call to `aabs` will always be safe for any `i32`, so we can use the `safe` keyword to say that this specific function is safe to call even though it is in an `unsafe extern` block.
Once we make this change, calling it no longer requires an `unsafe` block.
Here is the updated code
```rust
unsafe extern "C" {
safe fn abs(input: i32) -> i32;
}
fn main() {
println!("Absolute value of -3 according to C: {}", abs(-3));
}
```
Marking a function as `safe` does not inherently make it safe.
Instead, it is like a promise you are making to Rust that it *is* safe.
It is still your responsibility to make sure that the promise is kept.
### Calling Rust Functions form Other Languages
You can also use `extern` to create an interface that allows other languages to call Rust functions.
Instead of creating a whole `extern` block, we add the `extern` keyword and specify the ABI to use before the `fn` keyword for the relevant function.
Additionally we need to add a `#[unsafe(no_mangle)]` annotation to tell the Rust compiler not to mange the name of this function.
*Mangling* is when a compiler changes the name we have given a function to a different name that contains more information for other parts of the compilation process to consume but is less human readable.
Every programming language compiler mangles names slightly differently, so for a Rust function to be nameable by other languages, we must disable the Rust compiler's name mangling.
This is unsafe because there might be name collisions across libraries with the built-in mangling, so it is our responsibility to make sure the name we have exported is safe to export without mangling.
Here we make the `call_from_c` function accessible from C code, after it is compiled to a shared library and linked from C
```rust
#[unsafe(no_mangle)]
pub extern "C" fn call_from_c() {
println!("Just called a Rust function from C!");
}
```
This usage of `extern` does not require `unsafe`
## Accessing or Modifying a Mutable Static Variable
So far we have not talked about `global variables`, which Rust does support but can be problematic with Rust's ownership rules.
If two threads are accessing the same mutable global variable, it can cause a data race.
In Rust, global variables are called *static* variables.
Here shows an example declaration and use of a static variable with a string slice as a value.
```rust
static HELLO_WORLD: &str = "Hello, world!";
fn main() {
println!("name is: {HELLO_WORLD}");
}
```
Static variables are similar to constants, which we discussed in the ["Constants"]() section in Ch3.
The names of static variables are in `SCREAMING_SNAKE_CASE` by convention.
Static variables can only store references with the `'static` lifetime.
This means the Rust compiler can figure out the lifetime and we aren't required to annotate it explicitly.
Accessing an immutable static variable is safe.
A subtle difference between constants and immutable static variables is that values in a static variable have a fixed address in memory.
Using the value will always access the same data.
Constants, on the other hand are allowed to duplicate their data whenever they are used.
Another difference is that static variables can by mutable.
Accessing and modifying mutable static variables is *unsafe*.
Here shows how to declare, access and modify a mutable static variable named `COUNTER`.
```rust
static mut COUNTER: u32 = 0;
/// SAFETY: Calling this from more than a single thread at a time is undefined
/// behavior, so you *must* guarantee you only call it from a single thread at
/// a time.
unsafe fn add_to_count(inc: u32) {
unsafe {
COUNTER += inc;
}
}
fn main() {
unsafe {
// SAFETY: This is only called from a single thread in `main`.
add_to_count(3);
println!("COUNTER: {}", *(&raw const COUNTER));
}
}
```
Just like with regular variables, we specify mutability using the `mut` keyword.
Any code that reads or writes from `COUNTER` must be within an `unsafe` block.
The code above compiles and prints `COUNTER: 3` as expected because it is single threaded.
Having multiple thread access `COUNTER` would likely result in data races, so it is undefined behavior.
Due to this we need to mark the entire function as `unsafe` and document the safety limitation, so anyone calling this function knows what they are and are not allowed to do safely.
Whenever we write an unsafe function, it is idiomatic to write a comment starting with `SAFETY` and explaining what the caller needs to do to call the function safely.
Also whenever we perform an unsafe operation it is idiomatic to write a comment starting with `SAFETY` to explain how the safety rules are upheld.
As well, the compiler will not allow you to create references to a mutable static variable.
You can only access it via a raw pointer, created with one of the raw borrow operators.
This includes in cases where the reference is created invisibly as when it is used in the `println!` in this code listing.
The requirement that references to static mutable variables can only be created via raw pointers helps make the safety requirements for using them more obvious.
With mutable data that is globally accessible, it is difficult to ensure that there are no data races, which is why Rust considers mutable static variables to be unsafe.
Where it is possible it is preferred to use concurrency techniques and thread-safe smart pointers, so the compiler checks that data accessed from different threads is done safely.
## Implementing an Unsafe Trait
Additionally `unsafe` to implement an unsafe trait.
A trait is unsafe when at least one of its methods has some invariant that the compiler can't verify.
We declare that a trait is `unsafe` by adding the `unsafe` keyword before `trait` and marking the implementation of the trait as `unsafe` too.
Here is an example of this
```rust
unsafe trait Foo {
// methods go here
}
unsafe impl Foo for i32 {
// method implementations go here
}
fn main() {}
```
By using `unsafe impl`, we are promising that we will uphold the invariants that the compiler can't verify.
As an example, recall the `Sync` and `Send` marker traits we discussed in ["Extensible Concurrency with the `Sync` and `Send` Traits"]() section.
The compiler implements these traits automatically if our types are composed entirely of `Send` and `Sync` types.
If we implement a type that contains a type that is not `Send` or `Sync`, such as raw pointers, and we want to mark that type as `Send` or `Sync`, we must use `unsafe`.
Rust can't verify that our type upholds the guarantees that it can be safely sent across threads or accessed form multiple threads.
We need to do these checks manually and indicate as such with `unsafe`.
## Accessing Fields of a Union
The last superpower that works on with `unsafe` is accessing fields of a *union*.
A `union` is similar to a `struct`, but only one declared field is used in a particular instance at one time.
Unions are primarily used to interface with unions in C code.
Accessing union fields is unsafe because Rust can't guarantee the type of data currently being stored in the union instance.
You can learn more about unions in [the Rust Reference](https://doc.rust-lang.org/reference/items/unions.html).
## Using Miri to check unsafe code
When writing unsafe code, you may want to check that you have written actually is safe and correct.
Using [Miri](https://github.com/rust-lang/miri), an official Rust tool for detecting undefined behavior is one of the best ways to do it.
While the borrow checker is a *static* tool which works at compile time, Miri is a *dynamic* tool which works at runtime.
It checks your code by running your program or its test suite and detecting when you violate the rules it understands about how Rust should work.
Miri requires a nightly build of Rust (discussed in [Appendix G: How Rust is Made and "Nightly Rust"](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html)).
You can install both a nightly version of Rust and the Miri tool by typing `rustup +nightly component add miri`.
This does not change what version of Rust your project uses.
This only adds the tool to your system so you can use it when you want to.
You can run Miri on a project by typing cargo `+nightly miri run` or `cargo +nightly miri test`.
Here is an example of how useful when we run it on a previous example
```
$ cargo +nightly miri run
Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `/Users/chris/.rustup/toolchains/nightly-aarch64-apple-darwin/bin/cargo-miri runner target/miri/aarch64-apple-darwin/debug/unsafe-example`
warning: creating a shared reference to mutable static is discouraged
--> src/main.rs:14:33
|
14 | println!("COUNTER: {}", COUNTER);
| ^^^^^^^ shared reference to mutable static
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
= note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
= note: `#[warn(static_mut_refs)]` on by default
COUNTER: 3
```
It helpfully and correctly notices that we have shared references to mutable data and warns about it.
Here it does not tell us how to fix the problem, but it mean that we know there is a possible issue and can think about how to make sure it is safe.
In other cases, it can actually tell us that some code is *sure* to be wrong and make recommendations about how to fix it.
Miri will not catch *everything* you may get wrong when writing unsafe code.
Since it is a dynamic check, it only catches problems with code that actually gets run.
This means you will need to use it with good testing techniques to increase your confidence about the unsafe code you have written.
Additionally it does not cover every possible way your code can be unsound.
If Miri *does* catch a problem, you know that there is a bug, but just because Miri *doesn't* catch a bug doesn't mean there isn't a problem.
Miri can catch a lot despite this.
## When to Use Unsafe Code
Using `unsfe` to take one of the five superpowers, isn't wrong or frowned upon.
But it is trickier to get `unsafe` code correct because the compiler can't help uphold memory safety.
When you have a reason to use `unsafe` code, you can do so and having the explicit `unsafe` annotation makes it easier to tack down the source of problems when they occur.
When you write unsafe code, you can use Miri to help to be more confident that the code you wrote upholds Rust's rules.
For a deeper exploration of how to work effectively with unsafe Rust, read Rust's official guide on the subject the [Rustonomicon](https://doc.rust-lang.org/nomicon/).

View File

@ -1 +1 @@
{"rustc_fingerprint":953660965870803700,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.85.1 (4eb161250 2025-03-15)\nbinary: rustc\ncommit-hash: 4eb161250e340c8f48f66e2b929ef4a5bed7c181\ncommit-date: 2025-03-15\nhost: x86_64-unknown-linux-gnu\nrelease: 1.85.1\nLLVM version: 19.1.7\n","stderr":""},"2063776225603076451":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/brock/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"13331785392996375709":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/brock/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}
{"rustc_fingerprint":517133967738620428,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.86.0 (05f9846f8 2025-03-31)\nbinary: rustc\ncommit-hash: 05f9846f893b09a1be1fc8560e33fc3c815cfecb\ncommit-date: 2025-03-31\nhost: x86_64-pc-windows-msvc\nrelease: 1.86.0\nLLVM version: 19.1.7\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\Brock\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""}},"successes":{}}

11
hello/404.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Hello!</title>
</head>
<body>
<h1>Oops!</h1>
<p>Sorry, I don't know what you're asking for.</p>
</body>
</html>

7
hello/Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "hello"
version = "0.1.0"

6
hello/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "hello"
version = "0.1.0"
edition = "2024"
[dependencies]

11
hello/hello.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Hello!</title>
</head>
<body>
<h1>Hello!</h1>
<p>Hi from Rust</p>
</body>
</html>

82
hello/src/lib.rs Normal file
View File

@ -0,0 +1,82 @@
use std::{ sync::{ mpsc, Mutex, Arc }, thread };
pub struct ThreadPool {
workers: Vec<Worker>,
sender: Option<mpsc::Sender<Job>>,
}
impl ThreadPool {
/// Create a new ThreadPool.
///
/// The size is the number of threads in the pool.
///
/// # Panics
///
/// The `new` function will panic if the size is zero.
pub fn new(size: usize) -> ThreadPool {
assert!(size > 0);
let (sender, receiver) = mpsc::channel();
let receiver = Arc::new(Mutex::new(receiver));
let mut workers = Vec::with_capacity(size);
for id in 0..size {
workers.push(Worker::new(id, Arc::clone(&receiver)));
}
ThreadPool { workers, sender: Some(sender) }
}
pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
let job = Box::new(f);
self.sender.as_ref().unwrap().send(job).unwrap();
}
// ambitious side project
// pub fn build(size: usize) -> Result<ThreadPool, PoolCreationError> {}
}
impl Drop for ThreadPool {
fn drop(&mut self) {
drop(self.sender.take());
for worker in &mut self.workers.drain(..) {
println!("Shutting down worker {}", worker.id);
worker.thread.join().unwrap();
}
}
}
struct Worker {
id: usize,
thread: thread::JoinHandle<()>,
}
impl Worker {
fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
let thread = thread::spawn(move || {
loop {
let message = receiver.lock().unwrap().recv();
match message {
Ok(job) => {
println!("Worker {id} got a job; executing");
job();
}
Err(_) => {
println!("Worker {id} disconnected; shutting down.");
break;
}
}
}
});
Worker { id, thread }
}
}
type Job = Box<dyn FnOnce() + Send + 'static>;

74
hello/src/main.rs Normal file
View File

@ -0,0 +1,74 @@
use std::{
fs,
io::{ prelude::*, BufReader },
net::{ TcpListener, TcpStream },
thread,
time::Duration,
};
use hello::ThreadPool;
fn main() {
// this is not related I was just curious
// let test = fs::read_to_string("test.yaml").unwrap();
// println!("{}", test);
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
let pool = ThreadPool::new(4);
for stream in listener.incoming().take(2) {
let stream = stream.unwrap();
pool.execute(|| {
handle_connection(stream);
});
}
println!("Shutting down.");
}
fn handle_connection(mut stream: TcpStream) {
let buf_reader = BufReader::new(&stream);
// let http_request: Vec<_> = buf_reader
// .lines()
// .map(|result| result.unwrap())
// .take_while(|line| !line.is_empty())
// .collect();
let request_line = buf_reader.lines().next().unwrap().unwrap();
// no longer needed, here for debug and being useful
// println!("Request: {:#?}", http_request);
// if request_line == "GET / HTTP/1.1" {
// let status_line = "HTTP/1.1 200 OK";
// let contents = fs::read_to_string("./hello.html").unwrap();
// let length = contents.len();
// let res = format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}");
// stream.write_all(res.as_bytes()).unwrap();
// } else {
// let status_line = "HTTP/1.1 404 NOT FOUND";
// let contents = fs::read_to_string("404.html").unwrap();
// let length = contents.len();
// let res = format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}");
// stream.write_all(res.as_bytes()).unwrap();
// }
let (status_line, filename) = match &request_line[..] {
"GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"),
"GET /sleep HTTP/1.1" => {
thread::sleep(Duration::from_secs(5));
("HTTP/1.1 200 OK", "hello.html")
}
_ => ("HTTP/1.1 404 NOT FOUND", "404.html"),
};
let contents = fs::read_to_string(filename).unwrap();
let length = contents.len();
let res = format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}");
stream.write_all(res.as_bytes()).unwrap();
}

41
hello/test.yaml Normal file
View File

@ -0,0 +1,41 @@
Diamond Tier:
- Schulich School of Engineering:
LogoUrl: https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQj9L3ZGK6WtOmJbzxmCzRxwLXYKGC5SDcAKHb0ScfbUmbtG0IujQt6eQDaI_Pm9g4DZvc&usqp=CAU
Url: https://schulich.ucalgary.ca/
DescriptionAboutSponsor: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce eu magna in diam consectetur rhoncus vel nec turpis. Sed finibus mi eu sem varius faucibus. Donec semper erat et bibendum pharetra. Suspendisse cursus lorem sed nisi semper, a rutrum nunc luctus. Nunc ullamcorper enim id orci interdum ultrices. Donec vestibulum nunc vel nisl pretium tempus. Morbi quis ante et ligula eleifend eleifend. Proin bibendum maximus elit vitae congue. Vivamus egestas, ex in tempor posuere, ligula nunc iaculis massa, in imperdiet dui justo eu dolor. Nullam placerat velit quis sem mattis, laoreet pharetra elit tempor.
Platinum Tier:
- Platinum Sponsor Name:
LogoUrl:
Url:
DescriptionAboutSponsor:
Gold Tier:
- Suri:
LogoUrl: https://lh5.googleusercontent.com/WJsBsmcLypQhY0MMOLQtJSGFXrLQqPKNc3502rYUGKPCq_SfS9CxuoB3n541Kn9bKPm2b5aixCnYsCVYZAts2Y8xvmOHWL3nnbKtWUkE1KoFYYQ4bXUlikfF0NPIynxhzQ=w1280
Url: https://www.surimanufacturing.com/
DescriptionAboutSponsor:
- SKF:
LogoUrl: https://www.skf.com/v2/assets/img/skf-logo-white.svg
Url: https://www.skf.com/ca/en
DescriptionAboutSponsor: I am not sure
- WRMA:
LogoUrl: https://wildrosemx.com/wp-content/uploads/2021/08/wild-rose-motocross-calgary-rasterized.png
Url: https://wildrosemx.com/
DescriptionAboutSponsor:
Silver Tier:
- Encore Metals:
LogoUrl: https://www.encoremetals.com/assets/images/logos/encore-metals-logo.png
Url: https://www.encoremetals.com/
DescriptionAboutSponsor: Metal supplier
- CNOOC:
LogoUrl: https://cnoocinternational.com/img/cnooc-logo.png
Url: https://cnoocinternational.com/
DescriptionAboutSponsor:
Bronze Tier:
- Redbull:
LogoUrl: "https://img.redbull.com/redbullcom/static/redbullcom-logo_double-with-text.svg"
Url: https://www.redbull.com/ca-en/
DescriptionAboutSponsor:
- Canada Action:
LogoUrl:
Url:
DescriptionAboutSponsor:

View File

@ -1 +1 @@
{"rustc_fingerprint":953660965870803700,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.85.1 (4eb161250 2025-03-15)\nbinary: rustc\ncommit-hash: 4eb161250e340c8f48f66e2b929ef4a5bed7c181\ncommit-date: 2025-03-15\nhost: x86_64-unknown-linux-gnu\nrelease: 1.85.1\nLLVM version: 19.1.7\n","stderr":""},"2063776225603076451":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/brock/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"13331785392996375709":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/brock/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}
{"rustc_fingerprint":517133967738620428,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.86.0 (05f9846f8 2025-03-31)\nbinary: rustc\ncommit-hash: 05f9846f893b09a1be1fc8560e33fc3c815cfecb\ncommit-date: 2025-03-31\nhost: x86_64-pc-windows-msvc\nrelease: 1.86.0\nLLVM version: 19.1.7\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\Brock\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""}},"successes":{}}