10 |
11 |
--------------------------------------------------------------------------------
/examples/ch12-minigrep/poem.txt:
--------------------------------------------------------------------------------
1 | I'm nobody! Who are you?
2 | Are you nobody, too?
3 | Then there's a pair of us - don't tell!
4 | They'd banish us, you know.
5 |
6 | How dreary to be somebody!
7 | How public, like a frog
8 | To tell your name the livelong day
9 | To an admiring bog!
10 |
--------------------------------------------------------------------------------
/examples/ch13-minigrep/poem.txt:
--------------------------------------------------------------------------------
1 | I'm nobody! Who are you?
2 | Are you nobody, too?
3 | Then there's a pair of us - don't tell!
4 | They'd banish us, you know.
5 |
6 | How dreary to be somebody!
7 | How public, like a frog
8 | To tell your name the livelong day
9 | To an admiring bog!
10 |
--------------------------------------------------------------------------------
/examples/ch20-graceful-shutdown/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hello!
6 |
7 |
8 |
69 |
70 |
71 | ```
72 |
73 | And then here is the code for our server:
74 |
75 | ```rust title="src/main.rs"
76 | use std::{
77 | fs,
78 | io::{prelude::*, BufReader},
79 | net::{TcpListener, TcpStream},
80 | };
81 |
82 | fn main() {
83 | let port = 7878u16;
84 | let listen_address = format!("127.0.0.1:{port}");
85 | let listener = TcpListener::bind(listen_address).unwrap();
86 |
87 | println!("Listening on port {}", port);
88 |
89 | for stream in listener.incoming() {
90 | let stream = stream.unwrap();
91 |
92 | handle_connection(stream);
93 | }
94 | }
95 |
96 | fn handle_connection(mut stream: TcpStream) {
97 | let buf_reader = BufReader::new(&mut stream);
98 |
99 | // A line could be an error if it contains invalid
100 | // UTF-8, or if there's a problem reading from the
101 | // underlying stream. We ignore these errors here.
102 | let http_request: Vec<_> = buf_reader
103 | .lines()
104 | .map(|result| result.unwrap())
105 | .take_while(|line| !line.is_empty()) // Blank line is end of headers.
106 | .collect();
107 |
108 | let request_line = &http_request[0];
109 |
110 | println!("Incoming request for {}", request_line);
111 |
112 | if request_line == "GET / HTTP/1.1" {
113 | send_response(stream, 200, "OK", "hello.html");
114 | } else {
115 | send_response(stream, 404, "NOT FOUND", "404.html");
116 | }
117 | }
118 |
119 | fn send_response(mut stream: TcpStream, code: u16, reason: &str, filename: &str) {
120 | let contents = fs::read_to_string(filename).unwrap();
121 | let length = contents.len();
122 | let response =
123 | format!("HTTP/1.1 {code} {reason}\r\nContent-Length: {length}\r\n\r\n{contents}");
124 |
125 | stream.write_all(response.as_bytes()).unwrap();
126 | }
127 | ```
128 |
129 | If we `cargo run` this and point a browser at [http://localhost:7878/](http://localhost:7878/), we should see our web page!
130 |
131 | ## Listening to the TCP Connection
132 |
133 | Let's start with the `main` function. We call `TcpListener::bind` to start listening on a port. This returns a `TcpListener` instance, so it's basically a constructor for `TcpListener`. Note that we're binding to "127.0.0.1", so you'll only be able to access this web server from the same machine you're running it on. We could bind to "0.0.0.0" - the [unspecified address](https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html#method.is_unspecified) - to bind to all local interfaces. `bind` can fail for a variety of reasons. For example, if we tried to bind to port 80 and we weren't root, this would fail because we don't have sufficient permissions, or some other process might have already bound the port. We're glossing over all the error handling with a call to `unwrap`.
134 |
135 | Once we have out `TcpListener` we call `incoming` on it, which returns an iterator of `Result`. We'll get an item from this iterator every time a client tries to connect. Note this iterator will never return `None`! This loop is going to go on forever (or at least until we hit CTRL-C to terminate this program). A connection attempt can fail for a variety of reasons. In a production web server we'd want to handle these, but here we're once again just calling `unwrap`. Finally we hand of the connection to `handle_connection`.
136 |
137 | ## Parsing the Request
138 |
139 | Our `handle_connection` function creates a new buffered reader to read the incoming bytes from the stream. We user our reader to read in the request, split it into lines, then collect lines into a vector until we reach an empty line. As we've seen before, calling `collect` requires us to annotate the type of `http_request` so `collect` will know what kind of collection to return.
140 |
141 | Once we have our request, we call into `send_response` to generate an appropriate response back to the client.
142 |
143 | And that's all there is too it! Our server only runs in a single thread, so it can only handle a single request at a time. In the next section, we'll upgrade this server to run [in multiple threads](./ch20-02-multi-threaded-web-server.md).
144 |
--------------------------------------------------------------------------------
/docs/ch20/ch20-03-graceful-shutdown.md:
--------------------------------------------------------------------------------
1 | # 20.3 - Graceful Shutdown and Cleanup
2 |
3 | Right now when we hit CTRL-C to send an interrupt signal to our web server, it stops running, but it also stops any in-flight requests. Let's see if we can get our server to shut down gracefully.
4 |
5 | The basic strategy here is going to be to implement the `Drop` trait on `ThreadPool`. When the `ThreadPool` is dropped, we'll signal all the threads that they should stop accepting new requests and quit, and then we'll call `join` on each one to give them the time they need to finish up.
6 |
7 | If you're looking for the full source for this project, it's [in the GitHub repo](https://github.com/jwalton/rust-book-abridged/tree/master/examples/ch20-graceful-shutdown)
8 |
9 | ## Implementing the `Drop` Trait on `ThreadPool`
10 |
11 | One problem we're going to run into is that, in order to call `thread.join()`, we're going to have to move the `thread` out of the `Worker`. We can't move _part_ of a struct, so we're going to have to use the same trick we did in [chapter 17][chap17] and store the thread in an `Option` so we can set it to `None`.
12 |
13 | Calling `join` isn't enough though. This will wait until each thread quits, but right now the closure in each thread is an infinite loop! We need to somehow signal to the `Worker`'s thread that it should stop accepting new jobs. We can do this by dropping the `sender` half of the channel. This will cause the receiver to wake up and return an error. We'll have to pull the same trick we did with `thread` and store the `sender` in an `Option` to make this work, otherwise there's no way for us to drop the sender. We'll also want to handle the error from `recv` correctly instead of just panicking.
14 |
15 | Here's the updated library:
16 |
17 | ```rust title="src/lib.rs"
18 | use std::{
19 | sync::{mpsc, Arc, Mutex},
20 | thread::{self, JoinHandle},
21 | };
22 |
23 | type Job = Box;
24 |
25 | pub struct ThreadPool {
26 | workers: Vec,
27 | sender: Option>,
28 | }
29 |
30 | impl ThreadPool {
31 | /// Create a new ThreadPool.
32 | ///
33 | /// The size is the number of threads in the pool.
34 | ///
35 | /// # Panics
36 | ///
37 | /// The `new` function will panic if the size is zero.
38 | pub fn new(size: usize) -> ThreadPool {
39 | // Make sure `size` is valid.
40 | assert!(size > 0);
41 |
42 | // Create our sender and receiver
43 | let (sender, receiver) = mpsc::channel();
44 | let receiver = Arc::new(Mutex::new(receiver));
45 |
46 | // Create a new vector. Pre-allocate the vector
47 | // to be of length `size` so we know it can store
48 | // all of our threads.
49 | let mut workers = Vec::with_capacity(size);
50 |
51 | for id in 0..size {
52 | workers.push(Worker::new(id, Arc::clone(&receiver)));
53 | }
54 |
55 | ThreadPool {
56 | workers,
57 | sender: Some(sender),
58 | }
59 | }
60 |
61 | pub fn execute(&self, f: F)
62 | where
63 | F: FnOnce() + Send + 'static,
64 | {
65 | // Send our job to a Worker.
66 | let job = Box::new(f);
67 | self.sender.as_ref().unwrap().send(job).unwrap();
68 | }
69 | }
70 |
71 | impl Drop for ThreadPool {
72 | fn drop(&mut self) {
73 | // Drop the sender to force all the workers to finish up.
74 | drop(self.sender.take());
75 |
76 | for worker in &mut self.workers {
77 | println!("Shutting down worker {}", worker.id);
78 |
79 | // If there's a thread in this worker, wait for
80 | // it to finish. If thread is None, there's
81 | // nothing to clean up.
82 | if let Some(thread) = worker.thread.take() {
83 | thread.join().unwrap();
84 | }
85 | }
86 | }
87 | }
88 |
89 | struct Worker {
90 | id: usize,
91 | thread: Option>,
92 | }
93 |
94 | impl Worker {
95 | fn new(id: usize, receiver: Arc>>) -> Worker {
96 | let thread = thread::spawn(move || loop {
97 | let message = receiver.lock().unwrap().recv();
98 |
99 | match message {
100 | Ok(job) => {
101 | println!("Worker {id} got a job; executing.");
102 | job();
103 | }
104 | Err(_) => {
105 | println!("Worker {id} disconnected; shutting down.");
106 | break;
107 | }
108 | }
109 | });
110 |
111 | Worker {
112 | id,
113 | thread: Some(thread),
114 | }
115 | }
116 | }
117 | ```
118 |
119 | Now we just need some way to make the server shut down. A simple way to do this for testing is to modify `main`:
120 |
121 | ```rust title="src/main.rs"
122 | // --snip--
123 | for stream in listener.incoming().take(2) {
124 | // --snip--
125 | ```
126 |
127 | Now our server will shut down after two requests. Not exactly something we'd want to do in production, but it will prove our shutdown code is working here.
128 |
129 | ## Next Steps
130 |
131 | The original Rust book has some suggestions about places you could take this project further:
132 |
133 | > - Add more documentation to ThreadPool and its public methods.
134 | > - Add tests of the library's functionality.
135 | > - Change calls to unwrap to more robust error handling.
136 | > - Use ThreadPool to perform some task other than serving web requests.
137 | > - Find a thread pool crate on crates.io and implement a similar web server using the crate instead. Then compare its API and robustness to the thread pool we implemented.
138 |
139 | Another fun one might be to try to hook the SIGINT and SIGTERM signals so a CTRL-C will cause the server to shut down gracefully.
140 |
141 | This is as far as the original Rust book went, but you can continue on to our [special bonus chapter][chap21] to find out how we can rewrite this web server using async Rust!
142 |
143 | [chap17]: ../ch17-object-oriented-features.md "Chapter 17: Object Oriented Features of Rust"
144 | [chap21]: ../ch21-async.md "Chapter 21: Bonus Chapter: Async Programming"
145 |
--------------------------------------------------------------------------------
/docs/zz-appendix/appendix-04-useful-development-tools.md:
--------------------------------------------------------------------------------
1 | # Appendix D - Useful Development Tools
2 |
3 | This appendix was copied directly from ["The Rust Programming Language"](https://doc.rust-lang.org/stable/book/appendix-04-useful-development-tools.html).
4 |
5 | In this appendix, we talk about some useful development tools that the Rust
6 | project provides. We'll look at automatic formatting, quick ways to apply
7 | warning fixes, a linter, and integrating with IDEs.
8 |
9 | ## Automatic Formatting with `rustfmt`
10 |
11 | The `rustfmt` tool reformats your code according to the community code style.
12 | Many collaborative projects use `rustfmt` to prevent arguments about which
13 | style to use when writing Rust: everyone formats their code using the tool.
14 |
15 | To install `rustfmt`, enter the following:
16 |
17 | ```console
18 | $ rustup component add rustfmt
19 | ```
20 |
21 | This command gives you `rustfmt` and `cargo-fmt`, similar to how Rust gives you
22 | both `rustc` and `cargo`. To format any Cargo project, enter the following:
23 |
24 | ```console
25 | $ cargo fmt
26 | ```
27 |
28 | Running this command reformats all the Rust code in the current crate. This
29 | should only change the code style, not the code semantics. For more information
30 | on `rustfmt`, see [its documentation][rustfmt].
31 |
32 | [rustfmt]: https://github.com/rust-lang/rustfmt
33 |
34 | ## Fix Your Code with `rustfix`
35 |
36 | The rustfix tool is included with Rust installations and can automatically fix
37 | compiler warnings that have a clear way to correct the problem that's likely
38 | what you want. It's likely you've seen compiler warnings before. For example,
39 | consider this code:
40 |
41 | Filename: src/main.rs
42 |
43 | ```rust
44 | fn do_something() {}
45 |
46 | fn main() {
47 | for i in 0..100 {
48 | do_something();
49 | }
50 | }
51 | ```
52 |
53 | Here, we're calling the `do_something` function 100 times, but we never use the
54 | variable `i` in the body of the `for` loop. Rust warns us about that:
55 |
56 | ```console
57 | $ cargo build
58 | Compiling myprogram v0.1.0 (file:///projects/myprogram)
59 | warning: unused variable: `i`
60 | --> src/main.rs:4:9
61 | |
62 | 4 | for i in 0..100 {
63 | | ^ help: consider using `_i` instead
64 | |
65 | = note: #[warn(unused_variables)] on by default
66 |
67 | Finished dev [unoptimized + debuginfo] target(s) in 0.50s
68 | ```
69 |
70 | The warning suggests that we use `_i` as a name instead: the underscore
71 | indicates that we intend for this variable to be unused. We can automatically
72 | apply that suggestion using the `rustfix` tool by running the command `cargo
73 | fix`:
74 |
75 | ```console
76 | $ cargo fix
77 | Checking myprogram v0.1.0 (file:///projects/myprogram)
78 | Fixing src/main.rs (1 fix)
79 | Finished dev [unoptimized + debuginfo] target(s) in 0.59s
80 | ```
81 |
82 | When we look at *src/main.rs* again, we'll see that `cargo fix` has changed the
83 | code:
84 |
85 | ```rust title="src/main.rs"
86 | fn do_something() {}
87 |
88 | fn main() {
89 | for _i in 0..100 {
90 | do_something();
91 | }
92 | }
93 | ```
94 |
95 | The `for` loop variable is now named `_i`, and the warning no longer appears.
96 |
97 | You can also use the `cargo fix` command to transition your code between
98 | different Rust editions. Editions are covered in Appendix E.
99 |
100 | ## More Lints with Clippy
101 |
102 | The Clippy tool is a collection of lints to analyze your code so you can catch
103 | common mistakes and improve your Rust code.
104 |
105 | To install Clippy, enter the following:
106 |
107 | ```console
108 | $ rustup component add clippy
109 | ```
110 |
111 | To run Clippy's lints on any Cargo project, enter the following:
112 |
113 | ```console
114 | $ cargo clippy
115 | ```
116 |
117 | For example, say you write a program that uses an approximation of a
118 | mathematical constant, such as pi, as this program does:
119 |
120 | ```rust title="src/main.rs"
121 | fn main() {
122 | let x = 3.1415;
123 | let r = 8.0;
124 | println!("the area of the circle is {}", x * r * r);
125 | }
126 | ```
127 |
128 | Running `cargo clippy` on this project results in this error:
129 |
130 | ```text
131 | error: approximate value of `f{32, 64}::consts::PI` found
132 | --> src/main.rs:2:13
133 | |
134 | 2 | let x = 3.1415;
135 | | ^^^^^^
136 | |
137 | = note: `#[deny(clippy::approx_constant)]` on by default
138 | = help: consider using the constant directly
139 | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
140 | ```
141 |
142 | This error lets you know that Rust already has a more precise `PI` constant
143 | defined, and that your program would be more correct if you used the constant
144 | instead. You would then change your code to use the `PI` constant. The
145 | following code doesn't result in any errors or warnings from Clippy:
146 |
147 | ```rust title="src/main.rs"
148 | fn main() {
149 | let x = std::f64::consts::PI;
150 | let r = 8.0;
151 | println!("the area of the circle is {}", x * r * r);
152 | }
153 | ```
154 |
155 | For more information on Clippy, see [its documentation][clippy].
156 |
157 | [clippy]: https://github.com/rust-lang/rust-clippy
158 |
159 | ## IDE Integration Using `rust-analyzer`
160 |
161 | To help IDE integration, the Rust community recommends using
162 | [`rust-analyzer`][rust-analyzer]. This tool is a set of
163 | compiler-centric utilities that speaks the [Language Server Protocol][lsp], which is a specification for IDEs and programming languages to
165 | communicate with each other. Different clients can use `rust-analyzer`, such as
166 | [the Rust analyzer plug-in for Visual Studio Code][vscode].
167 |
168 | [lsp]: http://langserver.org/
169 | [vscode]: https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer
170 |
171 | Visit the `rust-analyzer` project's [home page][rust-analyzer]
172 | for installation instructions, then install the language server support in your
173 | particular IDE. Your IDE will gain abilities such as autocompletion, jump to
174 | definition, and inline errors.
175 |
176 | [rust-analyzer]: https://rust-analyzer.github.io
177 |
--------------------------------------------------------------------------------
/docs/ch10/ch10-01-generic-data-types.md:
--------------------------------------------------------------------------------
1 | # 10.1 - Generic Data Types
2 |
3 | ## In Function Definitions
4 |
5 | We can use generics to define a function that can accept different data types. This is similar to generics in TypeScript, Java, and Go, and just like template functions in C++.
6 |
7 | Here's an example of a function to find the largest number in a list:
8 |
9 | ```rust
10 | fn largest_i32(list: &[i32]) -> &i32 {
11 | let mut largest = &list[0];
12 |
13 | for item in list {
14 | if item > largest {
15 | largest = item;
16 | }
17 | }
18 |
19 | largest
20 | }
21 |
22 |
23 | fn main() {
24 | let number_list = vec![34, 50, 25, 100, 65];
25 |
26 | let result = largest_i32(&number_list);
27 | println!("The largest number is {}", result);
28 | }
29 | ```
30 |
31 | The problem with this function is that it can only accept a list of `i32`. If we wanted to write a version of this for `char` or for `u64`, the function signature would change, but the code in body would be identical. We can use generics here to write the function to accept any type by changing the function signature to:
32 |
33 | ```rust
34 | // This doesn't QUITE work...
35 | fn largest(list: &[T]) -> &T {
36 | ```
37 |
38 | The `` after the function name tells the compiler this is a generic function, so anywhere inside the function body where there's a `T`, we'll replace it with some concrete type when the function is actually called. (Or actually, when it's compiled. We'll compile one version of this function for each type it is used with.)
39 |
40 | If you actually try to compile the above though, `rustc` will complain. The problem is that `T` here could be an `i32` or a `u64`... but it could also be a `struct` or an `enum`. Inside the function we do `item > largest` - how would we decide if one struct was larger than another? We need to restrict what kinds of types can be used in place of T with a _trait bound_. In this case we only want to allow T to be a type that implements the `str::cmp::PartialOrd` trait. Types that implement this trait can be compared to each other:
41 |
42 | ```rust
43 | fn largest(list: &[T]) -> &T {
44 | ```
45 |
46 | :::info
47 | Why a single letter `T` for the generic type? It doesn't have to be; you can use `fn largest...` instead, and it will work. But in almost every language that supports something like generics, the convention is to use a single character.
48 | :::
49 |
50 | ## In Struct Definitions
51 |
52 | Generics aren't just for functions, we can also use them in structs. Here we have a `Point` struct which has an x and a y. Both x and y are type `T`, so they must both be the same type:
53 |
54 | ```rust
55 | struct Point {
56 | x: T,
57 | y: T,
58 | }
59 |
60 | fn main() {
61 | let integer = Point { x: 5, y: 10 };
62 | let unsigned: Point = Point { x: 9, y: 20 };
63 | let float = Point { x: 1.0, y: 4.0 };
64 |
65 | // This won't work, because we're trying to use two different types
66 | let wont_work = Point { x: 5, y: 4.0 };
67 | }
68 | ```
69 |
70 | If we want to support mixed types we can, but we'll have to redefine the struct to allow it:
71 |
72 | ```rust
73 | struct MultiPoint {
74 | x: T,
75 | y: U,
76 | }
77 | ```
78 |
79 | ## In Method Definitions
80 |
81 | If we create a struct with generic properties, it makes sense that we'll have to define methods that are generic too:
82 |
83 | ```rust
84 | pub struct Point {
85 | x: T,
86 | y: T,
87 | }
88 |
89 | impl Point {
90 | pub fn x(&self) -> &T {
91 | &self.x
92 | }
93 | }
94 | ```
95 |
96 | Note the `impl` - we need the `` here to let the compiler know that `T` is not a concrete type. Why? Because we can also declare methods only on specific concrete versions of a generic struct. This will add a `distance_from_origin` to `Point`, but not to any other Point, such as `Point`:
97 |
98 | ```rust
99 | impl Point {
100 | fn distance_from_origin(&self) -> f32 {
101 | (self.x.powi(2) + self.y.powi(2)).sqrt()
102 | }
103 | }
104 | ```
105 |
106 | We can also add generics to a method that are unrelated to the generics from the struct. Here we have a `Point` with two generic parameters called `X1` and `Y1`, and a generic method with two more `X2` and `Y2`:
107 |
108 | ```rust
109 | struct Point {
110 | x: X1,
111 | y: Y1,
112 | }
113 |
114 | impl Point {
115 | // Note that mixup takes `X2` and `Y2` generic types,
116 | // in addition to `X1` and `Y1` from the struct!
117 | fn mixup(self, other: Point) -> Point {
118 | Point {
119 | x: self.x,
120 | y: other.y,
121 | }
122 | }
123 | }
124 |
125 | fn main() {
126 | let p1 = Point { x: 5, y: 10.4 };
127 | let p2 = Point { x: "Hello", y: 'c' };
128 |
129 | let p3 = p1.mixup(p2);
130 |
131 | // Prints "p3.x = 5, p3.y = c".
132 | println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
133 | }
134 | ```
135 |
136 | ## In Enum Definitions
137 |
138 | We've already seen a few enums that use generics such as `Option` and `Result`:
139 |
140 | ```rust
141 | enum Option {
142 | Some(T),
143 | None,
144 | }
145 |
146 | enum Result {
147 | Ok(T),
148 | Err(E),
149 | }
150 | ```
151 |
152 | ## Performance of Code Using Generics
153 |
154 | Above we said that a you can use generics to define a function that can accept different data types, but it's perhaps more accurate to say that you can use them to easily create a whole bunch of functions, one for each data type. Much like C++ template functions, Rust generics are implemented using _monomorphization_, which is a fancy way of saying it generates a copy of your function for each generic type it was used with at compile time.
155 |
156 | In other words, if we go back to the `fn largest(list: &[T]) -> &T` we started this section with, if you were to call:
157 |
158 | ```rust
159 | let number_list = vec![34, 50, 25, 100, 65];
160 | let result = largest(&number_list);
161 |
162 | let char_list = vec!['y', 'm', 'a', 'q'];
163 | let result = largest(&char_list);
164 | ```
165 |
166 | then internally Rust would actually compile two different functions, a `largest` and a `largest`. This means generic have no runtime performance impact (but they do make your executable slightly larger).
167 |
168 | Continue to [10.02 - Traits](./ch10-02-traits.md).
169 |
--------------------------------------------------------------------------------
/docs/ch00-intro.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 1
3 | slug: /
4 | title: "The Rust Book (Abridged)"
5 | hide_title: true
6 | ---
7 |
8 |
14 |
15 | PDF version of this book is available [here](https://github.com/jwalton/rust-book-abridged/releases/latest/download/rust-book-abridged.pdf).
16 |
17 | ## What is this?
18 |
19 | This is an abridged - or perhaps a better word would be condensed - version of ["The Rust Programming Language"](https://doc.rust-lang.org/stable/book/title-page.html) (AKA "the Rust Book"). This is not an original work - all the chapter names and examples in this book have been copied verbatim from the original, but all of the prose has been rewritten from scratch, leaving out anything that's not about learning Rust. This book is about 1/2 the length of the original, but I don't think it is missing anything that an experienced software developer wouldn't already know.
20 |
21 | The Rust Book is a great resource for learning Rust, especially if you're new to programming. If you fall into this category, then I strongly suggest you put this book down and go read it instead. But... the Rust Book is quite wordy. If you're already familiar with one or more other programming languages, then you are likely already familiar with a lot of the concepts the book covers, and you might benefit from this shorter version. If you are already familiar with ideas like the stack and the heap, with test driven development, with the [DRY principle](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), then this might be a better read.
22 |
23 | This isn't meant to be a criticism of the Rust Book. It's excellent and well written, and there's a reason why it's highly recommended. The problem here is not with the original book, but more a mismatch when it comes to intended audience.
24 |
25 | ## What's different about this book?
26 |
27 | As mentioned above, the chapter names in this book are all the same as in the original, and in many cases the subsections in each chapter are the same. In most cases examples have been copied directly from the original. Keeping the original structure and examples hopefully makes it easy to jump back and forth between this book and the original, in case there are places where this book is unclear or covers concepts you are not familiar with.
28 |
29 | Where the original would build up a code example piece by piece, in most cases this version presents the finished code so you can read through it, and then points out some interesting parts. Where possible I've tried to add in material I think an advanced reader would find interesting. In some places this explains things in a different way than the original. This also adds an extra bonus chapter about async programming!
30 |
31 | I have a great deal of experience in TypeScript, Java, C/C++, Go, and a few other languages. I spent about two weeks putting this book together, reading the original, condensing it, and researching parts that weren't clear. Hopefully someone finds this useful! But I am new to Rust so if you find something that doesn't make sense, please feel free to [raise an issue](https://github.com/jwalton/rust-book-abridged).
32 |
33 | This book was written entirely by a human - none of this is generated by ChatGPT.
34 |
35 | If you enjoy this book, please [give it a star on GitHub](https://github.com/jwalton/rust-book-abridged).
36 |
37 | ## Table of Contents
38 |
39 | - [Chapter 1: Getting Started][chap1]
40 | - [Chapter 2: Guessing Game][chap2]
41 | - [Chapter 3: Common Programming Concepts][chap3]
42 | - [Chapter 4: Ownership, References, and Slices][chap4]
43 | - [Chapter 5: Using Structs to Structure Related Data][chap5]
44 | - [Chapter 6: Enums and Pattern Matching][chap6]
45 | - [Chapter 7: Managing Growing Projects with Packages, Crates, and Modules][chap7]
46 | - [Chapter 8: Common Collections][chap8]
47 | - [Chapter 9: Error Handling][chap9]
48 | - [Chapter 10: Generic Types, Traits, and Lifetimes][chap10]
49 | - [Chapter 11: Writing Automated Tests][chap11]
50 | - [Chapter 12: An I/O Project: Building a Command Line Program][chap12]
51 | - [Chapter 13: Functional Language Features: Iterators and Closures][chap13]
52 | - [Chapter 14: More About Cargo and Crates.io][chap14]
53 | - [Chapter 15: Smart Pointers][chap15]
54 | - [Chapter 16: Fearless Concurrency][chap16]
55 | - [Chapter 17: Object Oriented Features of Rust][chap17]
56 | - [Chapter 18: Patterns and Matching][chap18]
57 | - [Chapter 19: Advanced Features][chap19]
58 | - [Chapter 20: Multithreaded Web Server][chap20]
59 | - [Chapter 21: Bonus Chapter: Async Programming][chap21]
60 |
61 | [chap1]: ./ch01-getting-started.md "Chapter 1: Getting Started"
62 | [chap2]: ./ch02-guessing-game.md "Chapter 2: Guessing Game"
63 | [chap3]: ./ch03-common-programming-concepts.md "Chapter 3: Common Programming Concepts"
64 | [chap4]: ./ch04-ownership.md "Chapter 4: Ownership, References, and Slices"
65 | [chap5]: ./ch05-structs.md "Chapter 5: Using Structs to Structure Related Data"
66 | [chap6]: ./ch06-enums-and-pattern-matching.md "Chapter 6: Enums and Pattern Matching"
67 | [chap7]: ./ch07-packages-crates-modules.md "Chapter 7: Managing Growing Projects with Packages, Crates, and Modules"
68 | [chap8]: ./ch08-common-collections.md "Chapter 8: Common Collections"
69 | [chap9]: ./ch09-error-handling.md "Chapter 9: Error Handling"
70 | [chap10]: ./ch10/ch10-01-generic-data-types.md "Chapter 10: Generic Types, Traits, and Lifetimes"
71 | [chap11]: ./ch11-automated-tests.md "Chapter 11: Writing Automated Tests"
72 | [chap12]: ./ch12-io-project-cli.md "Chapter 12: An I/O Project: Building a Command Line Program"
73 | [chap13]: ./ch13-functional-language-features.md "Chapter 13: Functional Language Features: Iterators and Closures"
74 | [chap14]: ./ch14-more-about-cargo.md "Chapter 14: More About Cargo and Crates.io"
75 | [chap15]: ./ch15-smart-pointers.md "Chapter 15: Smart Pointers"
76 | [chap16]: ./ch16-fearless-concurrency.md "Chapter 16: Fearless Concurrency"
77 | [chap17]: ./ch17-object-oriented-features.md "Chapter 17: Object Oriented Features of Rust"
78 | [chap18]: ./ch18-patterns-and-matching.md "Chapter 18: Patterns and Matching"
79 | [chap19]: ./ch19/ch19-01-unsafe.md "Chapter 19: Advanced Features"
80 | [chap20]: ./ch20/ch20-01-single-threaded-web-server.md "Chapter 20: Multithreaded Web Server"
81 | [chap21]: ./ch21-async.md "Chapter 21: Bonus Chapter: Async Programming"
82 |
83 | (This version of this book is based on [commit c06006](https://github.com/rust-lang/book/commit/c06006157b14b3d47b5c716fc392b77f3b2e21ce)).
84 |
--------------------------------------------------------------------------------
/static/img/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
43 |
--------------------------------------------------------------------------------
/examples/ch21-async-web-server/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "autocfg"
7 | version = "1.1.0"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
10 |
11 | [[package]]
12 | name = "bitflags"
13 | version = "1.3.2"
14 | source = "registry+https://github.com/rust-lang/crates.io-index"
15 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
16 |
17 | [[package]]
18 | name = "bytes"
19 | version = "1.4.0"
20 | source = "registry+https://github.com/rust-lang/crates.io-index"
21 | checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
22 |
23 | [[package]]
24 | name = "cfg-if"
25 | version = "1.0.0"
26 | source = "registry+https://github.com/rust-lang/crates.io-index"
27 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
28 |
29 | [[package]]
30 | name = "hello-async"
31 | version = "0.1.0"
32 | dependencies = [
33 | "tokio",
34 | ]
35 |
36 | [[package]]
37 | name = "hermit-abi"
38 | version = "0.2.6"
39 | source = "registry+https://github.com/rust-lang/crates.io-index"
40 | checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
41 | dependencies = [
42 | "libc",
43 | ]
44 |
45 | [[package]]
46 | name = "libc"
47 | version = "0.2.142"
48 | source = "registry+https://github.com/rust-lang/crates.io-index"
49 | checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
50 |
51 | [[package]]
52 | name = "lock_api"
53 | version = "0.4.9"
54 | source = "registry+https://github.com/rust-lang/crates.io-index"
55 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
56 | dependencies = [
57 | "autocfg",
58 | "scopeguard",
59 | ]
60 |
61 | [[package]]
62 | name = "log"
63 | version = "0.4.17"
64 | source = "registry+https://github.com/rust-lang/crates.io-index"
65 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
66 | dependencies = [
67 | "cfg-if",
68 | ]
69 |
70 | [[package]]
71 | name = "mio"
72 | version = "0.8.6"
73 | source = "registry+https://github.com/rust-lang/crates.io-index"
74 | checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
75 | dependencies = [
76 | "libc",
77 | "log",
78 | "wasi",
79 | "windows-sys",
80 | ]
81 |
82 | [[package]]
83 | name = "num_cpus"
84 | version = "1.15.0"
85 | source = "registry+https://github.com/rust-lang/crates.io-index"
86 | checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
87 | dependencies = [
88 | "hermit-abi",
89 | "libc",
90 | ]
91 |
92 | [[package]]
93 | name = "parking_lot"
94 | version = "0.12.1"
95 | source = "registry+https://github.com/rust-lang/crates.io-index"
96 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
97 | dependencies = [
98 | "lock_api",
99 | "parking_lot_core",
100 | ]
101 |
102 | [[package]]
103 | name = "parking_lot_core"
104 | version = "0.9.7"
105 | source = "registry+https://github.com/rust-lang/crates.io-index"
106 | checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
107 | dependencies = [
108 | "cfg-if",
109 | "libc",
110 | "redox_syscall",
111 | "smallvec",
112 | "windows-sys",
113 | ]
114 |
115 | [[package]]
116 | name = "pin-project-lite"
117 | version = "0.2.9"
118 | source = "registry+https://github.com/rust-lang/crates.io-index"
119 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
120 |
121 | [[package]]
122 | name = "proc-macro2"
123 | version = "1.0.56"
124 | source = "registry+https://github.com/rust-lang/crates.io-index"
125 | checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
126 | dependencies = [
127 | "unicode-ident",
128 | ]
129 |
130 | [[package]]
131 | name = "quote"
132 | version = "1.0.26"
133 | source = "registry+https://github.com/rust-lang/crates.io-index"
134 | checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
135 | dependencies = [
136 | "proc-macro2",
137 | ]
138 |
139 | [[package]]
140 | name = "redox_syscall"
141 | version = "0.2.16"
142 | source = "registry+https://github.com/rust-lang/crates.io-index"
143 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
144 | dependencies = [
145 | "bitflags",
146 | ]
147 |
148 | [[package]]
149 | name = "scopeguard"
150 | version = "1.1.0"
151 | source = "registry+https://github.com/rust-lang/crates.io-index"
152 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
153 |
154 | [[package]]
155 | name = "signal-hook-registry"
156 | version = "1.4.1"
157 | source = "registry+https://github.com/rust-lang/crates.io-index"
158 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
159 | dependencies = [
160 | "libc",
161 | ]
162 |
163 | [[package]]
164 | name = "smallvec"
165 | version = "1.10.0"
166 | source = "registry+https://github.com/rust-lang/crates.io-index"
167 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
168 |
169 | [[package]]
170 | name = "socket2"
171 | version = "0.4.9"
172 | source = "registry+https://github.com/rust-lang/crates.io-index"
173 | checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
174 | dependencies = [
175 | "libc",
176 | "winapi",
177 | ]
178 |
179 | [[package]]
180 | name = "syn"
181 | version = "2.0.15"
182 | source = "registry+https://github.com/rust-lang/crates.io-index"
183 | checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
184 | dependencies = [
185 | "proc-macro2",
186 | "quote",
187 | "unicode-ident",
188 | ]
189 |
190 | [[package]]
191 | name = "tokio"
192 | version = "1.27.0"
193 | source = "registry+https://github.com/rust-lang/crates.io-index"
194 | checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001"
195 | dependencies = [
196 | "autocfg",
197 | "bytes",
198 | "libc",
199 | "mio",
200 | "num_cpus",
201 | "parking_lot",
202 | "pin-project-lite",
203 | "signal-hook-registry",
204 | "socket2",
205 | "tokio-macros",
206 | "windows-sys",
207 | ]
208 |
209 | [[package]]
210 | name = "tokio-macros"
211 | version = "2.0.0"
212 | source = "registry+https://github.com/rust-lang/crates.io-index"
213 | checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce"
214 | dependencies = [
215 | "proc-macro2",
216 | "quote",
217 | "syn",
218 | ]
219 |
220 | [[package]]
221 | name = "unicode-ident"
222 | version = "1.0.8"
223 | source = "registry+https://github.com/rust-lang/crates.io-index"
224 | checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
225 |
226 | [[package]]
227 | name = "wasi"
228 | version = "0.11.0+wasi-snapshot-preview1"
229 | source = "registry+https://github.com/rust-lang/crates.io-index"
230 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
231 |
232 | [[package]]
233 | name = "winapi"
234 | version = "0.3.9"
235 | source = "registry+https://github.com/rust-lang/crates.io-index"
236 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
237 | dependencies = [
238 | "winapi-i686-pc-windows-gnu",
239 | "winapi-x86_64-pc-windows-gnu",
240 | ]
241 |
242 | [[package]]
243 | name = "winapi-i686-pc-windows-gnu"
244 | version = "0.4.0"
245 | source = "registry+https://github.com/rust-lang/crates.io-index"
246 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
247 |
248 | [[package]]
249 | name = "winapi-x86_64-pc-windows-gnu"
250 | version = "0.4.0"
251 | source = "registry+https://github.com/rust-lang/crates.io-index"
252 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
253 |
254 | [[package]]
255 | name = "windows-sys"
256 | version = "0.45.0"
257 | source = "registry+https://github.com/rust-lang/crates.io-index"
258 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
259 | dependencies = [
260 | "windows-targets",
261 | ]
262 |
263 | [[package]]
264 | name = "windows-targets"
265 | version = "0.42.2"
266 | source = "registry+https://github.com/rust-lang/crates.io-index"
267 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
268 | dependencies = [
269 | "windows_aarch64_gnullvm",
270 | "windows_aarch64_msvc",
271 | "windows_i686_gnu",
272 | "windows_i686_msvc",
273 | "windows_x86_64_gnu",
274 | "windows_x86_64_gnullvm",
275 | "windows_x86_64_msvc",
276 | ]
277 |
278 | [[package]]
279 | name = "windows_aarch64_gnullvm"
280 | version = "0.42.2"
281 | source = "registry+https://github.com/rust-lang/crates.io-index"
282 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
283 |
284 | [[package]]
285 | name = "windows_aarch64_msvc"
286 | version = "0.42.2"
287 | source = "registry+https://github.com/rust-lang/crates.io-index"
288 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
289 |
290 | [[package]]
291 | name = "windows_i686_gnu"
292 | version = "0.42.2"
293 | source = "registry+https://github.com/rust-lang/crates.io-index"
294 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
295 |
296 | [[package]]
297 | name = "windows_i686_msvc"
298 | version = "0.42.2"
299 | source = "registry+https://github.com/rust-lang/crates.io-index"
300 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
301 |
302 | [[package]]
303 | name = "windows_x86_64_gnu"
304 | version = "0.42.2"
305 | source = "registry+https://github.com/rust-lang/crates.io-index"
306 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
307 |
308 | [[package]]
309 | name = "windows_x86_64_gnullvm"
310 | version = "0.42.2"
311 | source = "registry+https://github.com/rust-lang/crates.io-index"
312 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
313 |
314 | [[package]]
315 | name = "windows_x86_64_msvc"
316 | version = "0.42.2"
317 | source = "registry+https://github.com/rust-lang/crates.io-index"
318 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
319 |
--------------------------------------------------------------------------------
/docs/zz-appendix/appendix-03-derivable-traits.md:
--------------------------------------------------------------------------------
1 | # Appendix C: Derivable Traits
2 |
3 | This appendix was copied directly from ["The Rust Programming Language"](https://doc.rust-lang.org/stable/book/appendix-03-derivable-traits.html).
4 |
5 | In various places in the book, we've discussed the `derive` attribute, which
6 | you can apply to a struct or enum definition. The `derive` attribute generates
7 | code that will implement a trait with its own default implementation on the
8 | type you've annotated with the `derive` syntax.
9 |
10 | In this appendix, we provide a reference of all the traits in the standard
11 | library that you can use with `derive`. Each section covers:
12 |
13 | * What operators and methods deriving this trait will enable
14 | * What the implementation of the trait provided by `derive` does
15 | * What implementing the trait signifies about the type
16 | * The conditions in which you're allowed or not allowed to implement the trait
17 | * Examples of operations that require the trait
18 |
19 | If you want different behavior from that provided by the `derive` attribute,
20 | consult the [standard library documentation](https://doc.rust-lang.org/std/index.html)
21 | for each trait for details of how to manually implement them.
22 |
23 | These traits listed here are the only ones defined by the standard library that
24 | can be implemented on your types using `derive`. Other traits defined in the
25 | standard library don't have sensible default behavior, so it's up to you to
26 | implement them in the way that makes sense for what you're trying to accomplish.
27 |
28 | An example of a trait that can't be derived is `Display`, which handles
29 | formatting for end users. You should always consider the appropriate way to
30 | display a type to an end user. What parts of the type should an end user be
31 | allowed to see? What parts would they find relevant? What format of the data
32 | would be most relevant to them? The Rust compiler doesn't have this insight, so
33 | it can't provide appropriate default behavior for you.
34 |
35 | The list of derivable traits provided in this appendix is not comprehensive:
36 | libraries can implement `derive` for their own traits, making the list of
37 | traits you can use `derive` with truly open-ended. Implementing `derive`
38 | involves using a procedural macro, which is covered in the
39 | ["Macros"][macros] section of Chapter 19.
40 |
41 | ## `Debug` for Programmer Output
42 |
43 | The `Debug` trait enables debug formatting in format strings, which you
44 | indicate by adding `:?` within `{}` placeholders.
45 |
46 | The `Debug` trait allows you to print instances of a type for debugging
47 | purposes, so you and other programmers using your type can inspect an instance
48 | at a particular point in a program's execution.
49 |
50 | The `Debug` trait is required, for example, in use of the `assert_eq!` macro.
51 | This macro prints the values of instances given as arguments if the equality
52 | assertion fails so programmers can see why the two instances weren't equal.
53 |
54 | ## `PartialEq` and `Eq` for Equality Comparisons
55 |
56 | The `PartialEq` trait allows you to compare instances of a type to check for
57 | equality and enables use of the `==` and `!=` operators.
58 |
59 | Deriving `PartialEq` implements the `eq` method. When `PartialEq` is derived on
60 | structs, two instances are equal only if *all* fields are equal, and the
61 | instances are not equal if any fields are not equal. When derived on enums,
62 | each variant is equal to itself and not equal to the other variants.
63 |
64 | The `PartialEq` trait is required, for example, with the use of the
65 | `assert_eq!` macro, which needs to be able to compare two instances of a type
66 | for equality.
67 |
68 | The `Eq` trait has no methods. Its purpose is to signal that for every value of
69 | the annotated type, the value is equal to itself. The `Eq` trait can only be
70 | applied to types that also implement `PartialEq`, although not all types that
71 | implement `PartialEq` can implement `Eq`. One example of this is floating point
72 | number types: the implementation of floating point numbers states that two
73 | instances of the not-a-number (`NaN`) value are not equal to each other.
74 |
75 | An example of when `Eq` is required is for keys in a `HashMap` so the
76 | `HashMap` can tell whether two keys are the same.
77 |
78 | ## `PartialOrd` and `Ord` for Ordering Comparisons
79 |
80 | The `PartialOrd` trait allows you to compare instances of a type for sorting
81 | purposes. A type that implements `PartialOrd` can be used with the `<`, `>`,
82 | `<=`, and `>=` operators. You can only apply the `PartialOrd` trait to types
83 | that also implement `PartialEq`.
84 |
85 | Deriving `PartialOrd` implements the `partial_cmp` method, which returns an
86 | `Option` that will be `None` when the values given don't produce an
87 | ordering. An example of a value that doesn't produce an ordering, even though
88 | most values of that type can be compared, is the not-a-number (`NaN`) floating
89 | point value. Calling `partial_cmp` with any floating point number and the `NaN`
90 | floating point value will return `None`.
91 |
92 | When derived on structs, `PartialOrd` compares two instances by comparing the
93 | value in each field in the order in which the fields appear in the struct
94 | definition. When derived on enums, variants of the enum declared earlier in the
95 | enum definition are considered less than the variants listed later.
96 |
97 | The `PartialOrd` trait is required, for example, for the `gen_range` method
98 | from the `rand` crate that generates a random value in the range specified by a
99 | range expression.
100 |
101 | The `Ord` trait allows you to know that for any two values of the annotated
102 | type, a valid ordering will exist. The `Ord` trait implements the `cmp` method,
103 | which returns an `Ordering` rather than an `Option` because a valid
104 | ordering will always be possible. You can only apply the `Ord` trait to types
105 | that also implement `PartialOrd` and `Eq` (and `Eq` requires `PartialEq`). When
106 | derived on structs and enums, `cmp` behaves the same way as the derived
107 | implementation for `partial_cmp` does with `PartialOrd`.
108 |
109 | An example of when `Ord` is required is when storing values in a `BTreeSet`,
110 | a data structure that stores data based on the sort order of the values.
111 |
112 | ## `Clone` and `Copy` for Duplicating Values
113 |
114 | The `Clone` trait allows you to explicitly create a deep copy of a value, and
115 | the duplication process might involve running arbitrary code and copying heap
116 | data. See the [“Ways Variables and Data Interact:
117 | Clone”][ways-variables-and-data-interact-clone] section in
118 | Chapter 4 for more information on `Clone`.
119 |
120 | Deriving `Clone` implements the `clone` method, which when implemented for the
121 | whole type, calls `clone` on each of the parts of the type. This means all the
122 | fields or values in the type must also implement `Clone` to derive `Clone`.
123 |
124 | An example of when `Clone` is required is when calling the `to_vec` method on a
125 | slice. The slice doesn't own the type instances it contains, but the vector
126 | returned from `to_vec` will need to own its instances, so `to_vec` calls
127 | `clone` on each item. Thus, the type stored in the slice must implement `Clone`.
128 |
129 | The `Copy` trait allows you to duplicate a value by only copying bits stored on
130 | the stack; no arbitrary code is necessary. See the ["Stack-Only Data:
131 | Copy"][stack-only-data-copy] section in Chapter 4 for more
132 | information on `Copy`.
133 |
134 | The `Copy` trait doesn't define any methods to prevent programmers from
135 | overloading those methods and violating the assumption that no arbitrary code
136 | is being run. That way, all programmers can assume that copying a value will be
137 | very fast.
138 |
139 | You can derive `Copy` on any type whose parts all implement `Copy`. A type that
140 | implements `Copy` must also implement `Clone`, because a type that implements
141 | `Copy` has a trivial implementation of `Clone` that performs the same task as
142 | `Copy`.
143 |
144 | The `Copy` trait is rarely required; types that implement `Copy` have
145 | optimizations available, meaning you don't have to call `clone`, which makes
146 | the code more concise.
147 |
148 | Everything possible with `Copy` you can also accomplish with `Clone`, but the
149 | code might be slower or have to use `clone` in places.
150 |
151 | ## `Hash` for Mapping a Value to a Value of Fixed Size
152 |
153 | The `Hash` trait allows you to take an instance of a type of arbitrary size and
154 | map that instance to a value of fixed size using a hash function. Deriving
155 | `Hash` implements the `hash` method. The derived implementation of the `hash`
156 | method combines the result of calling `hash` on each of the parts of the type,
157 | meaning all fields or values must also implement `Hash` to derive `Hash`.
158 |
159 | An example of when `Hash` is required is in storing keys in a `HashMap`
160 | to store data efficiently.
161 |
162 | ## `Default` for Default Values
163 |
164 | The `Default` trait allows you to create a default value for a type. Deriving
165 | `Default` implements the `default` function. The derived implementation of the
166 | `default` function calls the `default` function on each part of the type,
167 | meaning all fields or values in the type must also implement `Default` to
168 | derive `Default`.
169 |
170 | The `Default::default` function is commonly used in combination with the struct
171 | update syntax discussed in the [“Creating Instances From Other Instances With
172 | Struct Update
173 | Syntax”][creating-instances-from-other-instances-with-struct-update-syntax]
174 | section in Chapter 5. You can customize a few fields of a struct and then
175 | set and use a default value for the rest of the fields by using
176 | `..Default::default()`.
177 |
178 | The `Default` trait is required when you use the method `unwrap_or_default` on
179 | `Option` instances, for example. If the `Option` is `None`, the method
180 | `unwrap_or_default` will return the result of `Default::default` for the type
181 | `T` stored in the `Option`.
182 |
183 | [creating-instances-from-other-instances-with-struct-update-syntax]: ../ch05-structs.md#creating-instances-from-other-instances-with-struct-update-syntax
184 | [stack-only-data-copy]: ../ch04-ownership.md#stack-only-data-copy
185 | [ways-variables-and-data-interact-clone]: ../ch04-ownership.md#there-can-only-be-one
186 | [macros]: ../ch19/ch19-05-macros.md#195---macros
187 |
--------------------------------------------------------------------------------
/docs/ch05-structs.md:
--------------------------------------------------------------------------------
1 | # 5 - Using Structs to Structure Related Data
2 |
3 | ## 5.1 - Defining and Instantiating Structs
4 |
5 | If you're coming from Go, then a struct in Rust is very similar to a struct in Go. It has public and private fields and you can define methods on a struct. If you're coming from JavaScript or Java, then a struct in Rust is similar to a class, except that a struct can't inherit from another struct. In any of these languages, a trait is very similar to an `interface`.
6 |
7 | If you're coming from C/C++, then a Rust struct is sort of like a C struct except you can add methods to it like a C++ class. If you're coming from some other language, I'm going to assume the concept of a `struct` or "object" isn't totally foreign to you.
8 |
9 | Here's what a struct looks like in Rust:
10 |
11 | ```rust
12 | struct User {
13 | active: bool,
14 | username: String,
15 | email: String,
16 | sign_in_count: u64,
17 | }
18 |
19 | fn main() {
20 | // Create an instance of User
21 | let mut myUser = User {
22 | active: true,
23 | username: String::from("jwalton"),
24 | email: String::from("jwalton@example.com"),
25 | sign_in_count: 1,
26 | };
27 |
28 | // Access fields with `.`
29 | println!("Name: {}", myUser.username);
30 |
31 | // Variable must be declared as `mut` if we want to be
32 | // able to modify the structure.
33 | myUser.email = String::from("other_email@example,com");
34 | }
35 | ```
36 |
37 | Note if you want to modify the contents of a struct, is has to be marked as `mut`. You can't mark individual fields as mutable - either the whole structure is, or none of it is.
38 |
39 | :::tip
40 | If you're curious about how Rust structures are laid out in memory, check [the Rust Reference's section on Type Layout](https://doc.rust-lang.org/reference/type-layout.html).
41 | :::
42 |
43 | ### Using the Field Init Shorthand
44 |
45 | Much like in JavaScript, we can initialize fields with a shorthand:
46 |
47 | ```rust
48 | fn build_user(email: String, username: String) -> User {
49 | User {
50 | active: true,
51 | // Instead of `username: username,` we can do:
52 | username,
53 | email,
54 | sign_in_count: 1,
55 | }
56 | }
57 | ```
58 |
59 | ### Creating Instances from Other Instances with Struct Update Syntax
60 |
61 | Rust has something called the _struct update syntax_ which allows us to copy fields from another struct (and which is very similar to the spread operator in JavaScript). This example will set the email of `user2`, and then copy all other fields from `user1`:
62 |
63 | ```rust
64 | let user2 = User {
65 | email: String::from("yet_another_email@example.com"),
66 | ..user1
67 | }
68 | ```
69 |
70 | When you store a field in a structure, or use the struct update syntax as in this example, from an ownership perspective you are moving that field. In this example, once we create `user2`, we can no longer use `user1` because its username field has been moved. If we had given `user2` an `email` and a `username`, then all the remaining fields we assigned from `user1` would be basic data types that implement the `Copy` trait. In this case, nothing would move, so `user1` would still be valid.
71 |
72 | ### Using Tuple Structs Without Named Fields to Create Different Types
73 |
74 | _Tuple structs_ are basically named tuples:
75 |
76 | ```rust
77 | struct Color(i32, i32, i32);
78 | struct Point(i32, i32, i32);
79 |
80 | fn main() {
81 | let black = Color(0, 0, 0);
82 | let origin = Point(0, 0, 0);
83 | }
84 | ```
85 |
86 | Note here that `Color` and `Point` are two different types, even though they have the same structure. If you have a function that accepted a `Color`, the compiler will complain if you try to pass in a `Point`.
87 |
88 | ### Unit-Like Structs Without Any Fields
89 |
90 | You can define a struct without any fields. These are used when you want to implement some trait ([see chapter 10][chap10]) but you don't have any data you actually want to store in your struct:
91 |
92 | ```rust
93 | struct AlwaysEqual;
94 |
95 | fn main() {
96 | let subject = AlwaysEqual;
97 | }
98 | ```
99 |
100 | You don't even need the `{}` to create an instance of `AlwaysEqual`.
101 |
102 | ### Ownership of Struct Data
103 |
104 | In the `User` struct above, we used a `String` type in the struct for the `username` and `email`. This means that the struct owns that `String`. When the struct is dropped, those two strings will be dropped too. We could instead have used an `&String` or `&str`, in which case the struct would store a reference to the string, and wouldn't own the string directly. The struct would be borrowing the string. We're not going to show an example of this though, because to do this we need something called a _lifetime annotation_, which we'll talk about in [chapter 10][chap10].
105 |
106 | ## 5.2 - An Example Program Using Structs
107 |
108 | A quick example of a program that uses a struct:
109 |
110 | ```rust
111 | struct Rectangle {
112 | width: u32,
113 | height: u32,
114 | }
115 |
116 | fn main() {
117 | let rect1 = Rectangle {
118 | width: 30,
119 | height: 50,
120 | };
121 |
122 | println!(
123 | "The area of the rectangle is {} square pixels.",
124 | area(&rect1)
125 | );
126 | }
127 |
128 | fn area(rectangle: &Rectangle) -> u32 {
129 | rectangle.width * rectangle.height
130 | }
131 | ```
132 |
133 | `area` takes an immutable reference to the `Rectangle` struct. We know when we call `area`, it won't modify our struct (even if `rect1` was declared as mutable in the caller). Passing a reference means the caller will retain ownership. Also, accessing fields on the borrowed struct doesn't move them.
134 |
135 | ### Adding Useful Functionality with Derived Traits
136 |
137 | It would be cool if we could "print" a rectangle:
138 |
139 | ```rust
140 | let rect1 = Rectangle {
141 | width: 30,
142 | height: 50,
143 | };
144 |
145 | println!("A rectangle: {}", rect1); // This will error.
146 | ```
147 |
148 | In Java and JavaScript we could to this with a `toString` method. In Go we could implement the `Stringer` interface. In Rust we have two different traits we can implement: `std::fmt::Display` and `Debug`. The Debug trait is one that's intended, as the name suggests, for debugging and it's the one we want here.
149 |
150 | Instead of implementing this trait ourselves, we can _derive_ this trait, which is a fancy way of saying we can let Rust generate the code for this trait for us:
151 |
152 | ```rust
153 | #[derive(Debug)]
154 | struct Rectangle {
155 | width: u32,
156 | height: u32,
157 | }
158 |
159 | fn main() {
160 | let rect1 = Rectangle {
161 | width: 30,
162 | height: 50,
163 | };
164 |
165 | println!("A rectangle: {:?}", rect1);
166 | }
167 | ```
168 |
169 | If you run this, it will print:
170 |
171 | ```txt
172 | A rectangle: Rectangle { width: 30, height: 50 }
173 | ```
174 |
175 | The placeholder in `println!` has changed from `{}` to `{:?}`, which lets `println!` know we want the debug output format. We could also use `{:#?}` to "pretty print" the output.
176 |
177 | There's also a handy macro called `dbg!` which will pretty-print the value, and the file name and source line. `dbg!(&rect1);` would print something like:
178 |
179 | ```txt
180 | [src/main.rs:13] &rect1 = Rectangle {
181 | width: 30,
182 | height: 50,
183 | }
184 | ```
185 |
186 | Note that unlike `println!`, `dbg!` takes ownership of the value passed in, so we pass a reference to `rect1` instead of passing `rect1` directly to prevent this. There are a number of other derivable traits - see [Appendix C][appc]. And, again, to learn more about traits see [chapter 10][chap10].
187 |
188 | ## 5.3 - Method Syntax
189 |
190 | _Methods_ are functions defined on a struct. Their first parameter is always `self`, which represents the instance of the struct the method is being called on (similar to `this` in other languages).
191 |
192 | ```rust
193 | #[derive(Debug)]
194 | struct Rectangle {
195 | width: u32,
196 | height: u32,
197 | }
198 |
199 | impl Rectangle {
200 | fn area(&self) -> u32 {
201 | self.width * self.height
202 | }
203 |
204 | // Returns true if `other` Rectangle can fit inside this one.
205 | fn can_hold(&self, other: &Rectangle) -> bool {
206 | self.width > other.width && self.height > other.height
207 | }
208 | }
209 |
210 | fn main() {
211 | let rect1 = Rectangle {
212 | width: 30,
213 | height: 50,
214 | };
215 |
216 | println!(
217 | "The area of the rectangle is {} square pixels.",
218 | rect1.area()
219 | );
220 | }
221 | ```
222 |
223 | The `impl` (implementation) block defines methods and associated functions on the Rectangle type. `area` takes a reference to `&self`, which is actually a short form for `self: &Self`.
224 |
225 | A method will generally have one of three different parameters for `self`:
226 |
227 | - `fn method(&self)` is a method with an immutable borrow of self. Like any other parameter, it is immutable by default.
228 | - `fn method(& mut self)` is a method with a mutable borrow of self, which means this method can change fields on `self`.
229 | - `fn method(mut self)` is a method that takes ownership of self. These methods you won't see as often, because once you call such a method the receiver is no longer valid, but these methods are often used to transform a value into some other structure. An example is the `map` method on iterator, which destroys the original iterator and returns a new one.
230 |
231 | You can have a method on a struct with the same name as one of the fields. This is most commonly used to add a _getter_ method to a struct. You can make it so a rectangle has a private `width: u32` field, and a public `width(): u32` method, which effectively makes `width` read-only. (What are public and private fields and methods? You'll have to wait for [chapter 7][chap7].)
232 |
233 | ### Automatic Referencing and Dereferencing
234 |
235 | You may have noticed that `area` takes a ref to self, but we called it as `rect1.area()` and not `(&rect1).area()`. Much like in Go, Rust has automatic referencing and dereferencing. When you call a method on a struct, Rust will automatically add in the `&`, `&mut`, or `*` so the object matches the signature of the method.
236 |
237 | Continue to [chapter 6][chap6].
238 |
239 | [chap6]: ./ch06-enums-and-pattern-matching.md "Chapter 6: Enums and Pattern Matching"
240 | [chap7]: ./ch07-packages-crates-modules.md "Chapter 7: Managing Growing Projects with Packages, Crates, and Modules"
241 | [chap10]: ./ch10/ch10-01-generic-data-types.md "Chapter 10: Generic Types, Traits, and Lifetimes"
242 | [appc]: ./zz-appendix/appendix-03-derivable-traits.md
243 |
--------------------------------------------------------------------------------
/docs/ch20/ch20-02-multi-threaded-web-server.md:
--------------------------------------------------------------------------------
1 | # 20.2 - Turning Our Single-Threaded Server into a Multithreaded Server
2 |
3 | ## Simulating a Slow Request in the Current Server Implementation
4 |
5 | Since our web server is single threaded, it will completely handle one request before moving on to the next request in the queue. If we had a request that took a long time to process, it would hold up all the subsequent requests.
6 |
7 | ```rust title="src/main.rs"
8 | use std::{
9 | fs,
10 | io::{prelude::*, BufReader},
11 | net::{TcpListener, TcpStream},
12 | thread,
13 | time::Duration,
14 | };
15 |
16 | // --snip--
17 |
18 | fn handle_connection(mut stream: TcpStream) {
19 | // --snip--
20 |
21 | match &request_line[..] {
22 | "GET / HTTP/1.1" => send_response(stream, 200, "OK", "hello.html"),
23 | "GET /sleep HTTP/1.1" => {
24 | thread::sleep(Duration::from_secs(5));
25 | send_response(stream, 200, "OK", "hello.html");
26 | }
27 | _ => send_response(stream, 404, "NOT FOUND", "404.html")
28 | }
29 |
30 | // --snip--
31 | }
32 | ```
33 |
34 | We've switched from an `if` to a `match`, and added a "/sleep" route. We have to pass `&request_line[..]` to the match expression to explicitly convert it to a slice here, because `match` doesn't do automatic dereferencing like the equality method does.
35 |
36 | The important thing here is, if you open up your browser and try to load [http://localhost:7878/sleep](http://localhost:7878/sleep), it'll take about five seconds for the page to load. If you tap CTRL-R to reload the page twice in quick succession, it will take about 10 seconds! Your browser sent two requests, and is waiting for the second one to finish.
37 |
38 | ## Improving Throughput with a Thread Pool
39 |
40 | We _could_ solve this problem by just creating a new thread for each incoming connection:
41 |
42 | ```rust
43 | for stream in listener.incoming() {
44 | let stream = stream.unwrap();
45 |
46 | thread::spawn(|| {
47 | handle_connection(stream);
48 | });
49 | }
50 | ```
51 |
52 | Starting up an OS level thread has some costs associated with it, and if we start up too many of them we may run out of system resources, so a common pattern for a situation like this is to use a _thread pool_. We pre-allocate a number of threads that will be sitting idle, and then whenever a request comes in we hand it off to an idle worker from the pool.
53 |
54 | ```rust
55 | let pool = ThreadPool::new(4);
56 | for stream in listener.incoming() {
57 | let stream = stream.unwrap();
58 |
59 | pool.execute(|| {
60 | handle_connection(stream);
61 | });
62 | }
63 | ```
64 |
65 | That's all there is too it! Except Rust can't find the `ThreadPool` symbol. We'll have to bring it into scope to use it, but before that we'll have to build a ThreadPool!
66 |
67 | ## Building a ThreadPool
68 |
69 | Before we show the code for a ThreadPool, let's take a moment to think through what it's going to look like. We want to store a collection of threads. We won't know the number of threads until runtime so a vector is a reasonable choice here, but what exactly is being stored in the vector? How do you store a thread? If we have a look at the signature for `thread::spawn`:
70 |
71 | ```rust
72 | pub fn spawn(f: F) -> JoinHandle
73 | where
74 | F: FnOnce() -> T,
75 | F: Send + 'static,
76 | T: Send + 'static,
77 | {
78 | // --snip--
79 | }
80 | ```
81 |
82 | We can see it returns a `JoinHandle`. The `T` here is the type the thread will "return" when it completes, but our threads are never going to complete, so we'll store a `Vec>`. Actually, in order to make our lives a little easier at debugging time, we'll give each thread a unique ID and combine ID and `JoinHandle<()>` into a `Worker` and then store a `Vec`.
83 |
84 | Here's what the `Worker` is going to look like:
85 |
86 | ```rust
87 | struct Worker {
88 | id: usize,
89 | thread: JoinHandle<()>,
90 | }
91 |
92 | impl Worker {
93 | /// Create a new Worker with the given id.
94 | pub fn new(id: usize) -> Worker {
95 | let thread = thread::spawn(|| {
96 | todo!("Zhu Li, do the thing!");
97 | });
98 |
99 | Worker { id, thread }
100 | }
101 | }
102 | ```
103 |
104 | We're going to execute jobs on these threads, but what's a job? We already know they are closures. Since we want our API to be similar to `thread::spawn`, a job is going to be the same type as `F` in `thread::spawn` above. It'll be `FnOnce()` since it's a function we want to call exactly once. It will also need to be `Send` so we can transfer it to our worker thread, and `'static` because we don't know how long the thread will take to run. So we'll define `Job` as an alias for:
105 |
106 | ```rust
107 | type Job = Box;
108 | ```
109 |
110 | Whenever we call `pool.execute` and pass in a job, we want that job to be run by a free thread from the pool. How does this happen? What happens inside the thread we spawn inside the Worker? We've conveniently left this out of our `Worker` above. There are many ways we could do this, but the approach we will use here is to send each job over a channel.
111 |
112 | Each `Worker` will hang on to the receiver side of a channel. The thread inside a `Worker` can just iterate on the channel and execute each job it receives in series. But you may recall that the channels we've been using are from the `mpsc` library, which stands for "multiple producers, single consumer". If we're creating four threads, we could create four channels and give one receiver from each to each worker. In this case, though, we'd have to decide which sender to send a new job to. How do we know which threads are free to accept new jobs?
113 |
114 | What we really want here is the other way around: "single producer, multiple consumers". We know how to share a variable between multiple threads though; instead of having multiple channels, we can have just a single channel. We can wrap the receiver in a `Mutex`, and then wrap that in an `Arc`, and multiple threads will be able to safely call into the receiver one-at-a-time to fetch jobs.
115 |
116 | Here's the code:
117 |
118 | ```rust title="src/lib.rs"
119 | use std::{
120 | sync::{mpsc, Arc, Mutex},
121 | thread::{self, JoinHandle},
122 | };
123 |
124 | type Job = Box;
125 |
126 | pub struct ThreadPool {
127 | workers: Vec,
128 | sender: mpsc::Sender,
129 | }
130 |
131 | impl ThreadPool {
132 | /// Create a new ThreadPool.
133 | ///
134 | /// The size is the number of threads in the pool.
135 | ///
136 | /// # Panics
137 | ///
138 | /// The `new` function will panic if the size is zero.
139 | pub fn new(size: usize) -> ThreadPool {
140 | // Make sure `size` is valid.
141 | assert!(size > 0);
142 |
143 | // Create our sender and receiver
144 | let (sender, receiver) = mpsc::channel();
145 | let receiver = Arc::new(Mutex::new(receiver));
146 |
147 | // Create a new vector. Pre-allocate the vector
148 | // to be of length `size` so we know it can store
149 | // all of our threads.
150 | let mut workers = Vec::with_capacity(size);
151 |
152 | // Create new workers and add them to the pool.
153 | for id in 0..size {
154 | workers.push(Worker::new(id, Arc::clone(&receiver)));
155 | }
156 |
157 | ThreadPool {
158 | workers,
159 | sender,
160 | }
161 | }
162 |
163 | pub fn execute(&self, f: F)
164 | where
165 | F: FnOnce() + Send + 'static,
166 | {
167 | // Send our job to a Worker.
168 | let job = Box::new(f);
169 | self.sender.send(job).unwrap();
170 | }
171 | }
172 |
173 | struct Worker {
174 | id: usize,
175 | thread: JoinHandle<()>,
176 | }
177 |
178 | impl Worker {
179 | /// Create a new Worker with the given id.
180 | pub fn new(id: usize, receiver: Arc>>) -> Worker {
181 | let thread = thread::spawn(move || loop {
182 | let job = receiver.lock().unwrap().recv().unwrap();
183 | println!("Worker {id} got a job; executing.");
184 | job();
185 | });
186 |
187 | Worker { id, thread }
188 | }
189 | }
190 | ```
191 |
192 | If you give this a try, it should work (although you'll get some compiler warnings)! If you visit "/sleep", wait for it to load, and then double-tap "CTRL-R" to reload the page, the page should reload in about five seconds instead of ten. If you're running into problems, check out the [code in the GitHub repo](https://github.com/jwalton/rust-book-abridged/tree/master/examples/ch20-multi-threaded-web-server).
193 |
194 | One thing you might have expected us to do in the worker was:
195 |
196 | ```rust
197 | let thread = thread::spawn(move || loop {
198 | // This is not so good...
199 | for job in receiver.lock().unwrap().iter() {
200 | println!("Worker {id} got a job; executing.");
201 | job();
202 | }
203 | });
204 | ```
205 |
206 | If you give this a try, it will appear to work, but our "double-reload" example will be back to ten seconds again. Why? Because this code is equivalent to:
207 |
208 | ```rust
209 | let thread = thread::spawn(move || loop {
210 | // Take the lock on the mutex...
211 | let rx = receiver.lock().unwrap();
212 | // Then loop forever, never giving up the lock.
213 | for job in rx.iter() {
214 | println!("Worker {id} got a job; executing.");
215 | job();
216 | }
217 | });
218 | ```
219 |
220 | One thread will take the mutex and then loop with it held, so one of our threads doing all the work.
221 |
222 | There are also a few things wrong with this code as it stands. First, we're obviously glossing over some error handling, which is fine for this example. Second, if you reload the "/sleep" route many times, you'll find eventually it will start taking a long time to load. What's happening here is that we're queueing up jobs in the channel.
223 |
224 | Ideally if all the workers are busy, we'd return a 503 to let the client know we are too busy to handle the request. We could do this in a few ways; we could use the `atomic` package to increment a counter when we start a job and decrement it when we finish one, so we know how many jobs are in progress. There's also a `channel::sync_channel` which allows creating a channel with a bounded size. The sender in this case has a `try_send` which will return an error if the channel is full. This is left as an exercise for the reader.
225 |
226 | Next we'll look at how to adapt our web server to [shut down gracefully](ch20-03-graceful-shutdown.md).
227 |
--------------------------------------------------------------------------------
/docs/zz-appendix/appendix-02-operators.md:
--------------------------------------------------------------------------------
1 | # Appendix B: Operators and Symbols
2 |
3 | This appendix was copied directly from ["The Rust Programming Language"](https://doc.rust-lang.org/stable/book/appendix-02-operators.html).
4 |
5 | This appendix contains a glossary of Rust's syntax, including operators and
6 | other symbols that appear by themselves or in the context of paths, generics,
7 | trait bounds, macros, attributes, comments, tuples, and brackets.
8 |
9 | ## Operators
10 |
11 | Table B-1 contains the operators in Rust, an example of how the operator would
12 | appear in context, a short explanation, and whether that operator is
13 | overloadable. If an operator is overloadable, the relevant trait to use to
14 | overload that operator is listed.
15 |
16 | ### Table B-1: Operators
17 |
18 | | Operator | Example | Explanation | Overloadable? |
19 | |----------|---------|-------------|---------------|
20 | | `!` | `ident!(...)`, `ident!{...}`, `ident![...]` | Macro expansion | |
21 | | `!` | `!expr` | Bitwise or logical complement | `Not` |
22 | | `!=` | `expr != expr` | Nonequality comparison | `PartialEq` |
23 | | `%` | `expr % expr` | Arithmetic remainder | `Rem` |
24 | | `%=` | `var %= expr` | Arithmetic remainder and assignment | `RemAssign` |
25 | | `&` | `&expr`, `&mut expr` | Borrow | |
26 | | `&` | `&type`, `&mut type`, `&'a type`, `&'a mut type` | Borrowed pointer type | |
27 | | `&` | `expr & expr` | Bitwise AND | `BitAnd` |
28 | | `&=` | `var &= expr` | Bitwise AND and assignment | `BitAndAssign` |
29 | | `&&` | `expr && expr` | Short-circuiting logical AND | |
30 | | `*` | `expr * expr` | Arithmetic multiplication | `Mul` |
31 | | `*=` | `var *= expr` | Arithmetic multiplication and assignment | `MulAssign` |
32 | | `*` | `*expr` | Dereference | `Deref` |
33 | | `*` | `*const type`, `*mut type` | Raw pointer | |
34 | | `+` | `trait + trait`, `'a + trait` | Compound type constraint | |
35 | | `+` | `expr + expr` | Arithmetic addition | `Add` |
36 | | `+=` | `var += expr` | Arithmetic addition and assignment | `AddAssign` |
37 | | `,` | `expr, expr` | Argument and element separator | |
38 | | `-` | `- expr` | Arithmetic negation | `Neg` |
39 | | `-` | `expr - expr` | Arithmetic subtraction | `Sub` |
40 | | `-=` | `var -= expr` | Arithmetic subtraction and assignment | `SubAssign` |
41 | | `->` | `fn(...) -> type`, |...| -> type | Function and closure return type | |
42 | | `.` | `expr.ident` | Member access | |
43 | | `..` | `..`, `expr..`, `..expr`, `expr..expr` | Right-exclusive range literal | `PartialOrd` |
44 | | `..=` | `..=expr`, `expr..=expr` | Right-inclusive range literal | `PartialOrd` |
45 | | `..` | `..expr` | Struct literal update syntax | |
46 | | `..` | `variant(x, ..)`, `struct_type { x, .. }` | “And the rest” pattern binding | |
47 | | `...` | `expr...expr` | (Deprecated, use `..=` instead) In a pattern: inclusive range pattern | |
48 | | `/` | `expr / expr` | Arithmetic division | `Div` |
49 | | `/=` | `var /= expr` | Arithmetic division and assignment | `DivAssign` |
50 | | `:` | `pat: type`, `ident: type` | Constraints | |
51 | | `:` | `ident: expr` | Struct field initializer | |
52 | | `:` | `'a: loop {...}` | Loop label | |
53 | | `;` | `expr;` | Statement and item terminator | |
54 | | `;` | `[...; len]` | Part of fixed-size array syntax | |
55 | | `<<` | `expr << expr` | Left-shift | `Shl` |
56 | | `<<=` | `var <<= expr` | Left-shift and assignment | `ShlAssign` |
57 | | `<` | `expr < expr` | Less than comparison | `PartialOrd` |
58 | | `<=` | `expr <= expr` | Less than or equal to comparison | `PartialOrd` |
59 | | `=` | `var = expr`, `ident = type` | Assignment/equivalence | |
60 | | `==` | `expr == expr` | Equality comparison | `PartialEq` |
61 | | `=>` | `pat => expr` | Part of match arm syntax | |
62 | | `>` | `expr > expr` | Greater than comparison | `PartialOrd` |
63 | | `>=` | `expr >= expr` | Greater than or equal to comparison | `PartialOrd` |
64 | | `>>` | `expr >> expr` | Right-shift | `Shr` |
65 | | `>>=` | `var >>= expr` | Right-shift and assignment | `ShrAssign` |
66 | | `@` | `ident @ pat` | Pattern binding | |
67 | | `^` | `expr ^ expr` | Bitwise exclusive OR | `BitXor` |
68 | | `^=` | `var ^= expr` | Bitwise exclusive OR and assignment | `BitXorAssign` |
69 | | | | pat | pat | Pattern alternatives | |
70 | | | | expr | expr | Bitwise OR | `BitOr` |
71 | | |= | var |= expr | Bitwise OR and assignment | `BitOrAssign` |
72 | | || | expr || expr | Short-circuiting logical OR | |
73 | | `?` | `expr?` | Error propagation | |
74 |
75 | ## Non-operator Symbols
76 |
77 | The following list contains all symbols that don’t function as operators; that
78 | is, they don’t behave like a function or method call.
79 |
80 | Table B-2 shows symbols that appear on their own and are valid in a variety of
81 | locations.
82 |
83 | ### Table B-2: Stand-Alone Syntax
84 |
85 | | Symbol | Explanation |
86 | |--------|-------------|
87 | | `'ident` | Named lifetime or loop label |
88 | | `...u8`, `...i32`, `...f64`, `...usize`, etc. | Numeric literal of specific type |
89 | | `"..."` | String literal |
90 | | `r"..."`, `r#"..."#`, `r##"..."##`, etc. | Raw string literal, escape characters not processed |
91 | | `b"..."` | Byte string literal; constructs an array of bytes instead of a string |
92 | | `br"..."`, `br#"..."#`, `br##"..."##`, etc. | Raw byte string literal, combination of raw and byte string literal |
93 | | `'...'` | Character literal |
94 | | `b'...'` | ASCII byte literal |
95 | | |...| expr | Closure |
96 | | `!` | Always empty bottom type for diverging functions |
97 | | `_` | "Ignored" pattern binding; also used to make integer literals readable |
98 |
99 | Table B-3 shows symbols that appear in the context of a path through the module
100 | hierarchy to an item.
101 |
102 | ### Table B-3: Path-Related Syntax
103 |
104 | | Symbol | Explanation |
105 | |--------|-------------|
106 | | `ident::ident` | Namespace path |
107 | | `::path` | Path relative to the crate root (i.e., an explicitly absolute path) |
108 | | `self::path` | Path relative to the current module (i.e., an explicitly relative path).
109 | | `super::path` | Path relative to the parent of the current module |
110 | | `type::ident`, `::ident` | Associated constants, functions, and types |
111 | | `::...` | Associated item for a type that cannot be directly named (e.g., `<&T>::...`, `<[T]>::...`, etc.) |
112 | | `trait::method(...)` | Disambiguating a method call by naming the trait that defines it |
113 | | `type::method(...)` | Disambiguating a method call by naming the type for which it’s defined |
114 | | `::method(...)` | Disambiguating a method call by naming the trait and type |
115 |
116 | Table B-4 shows symbols that appear in the context of using generic type
117 | parameters.
118 |
119 | ### Table B-4: Generics
120 |
121 | | Symbol | Explanation |
122 | |--------|-------------|
123 | | `path<...>` | Specifies parameters to generic type in a type (e.g., `Vec`) |
124 | | `path::<...>`, `method::<...>` | Specifies parameters to generic type, function, or method in an expression; often referred to as turbofish (e.g., `"42".parse::()`) |
125 | | `fn ident<...> ...` | Define generic function |
126 | | `struct ident<...> ...` | Define generic structure |
127 | | `enum ident<...> ...` | Define generic enumeration |
128 | | `impl<...> ...` | Define generic implementation |
129 | | `for<...> type` | Higher-ranked lifetime bounds |
130 | | `type` | A generic type where one or more associated types have specific assignments (e.g., `Iterator`) |
131 |
132 | Table B-5 shows symbols that appear in the context of constraining generic type
133 | parameters with trait bounds.
134 |
135 | ### Table B-5: Trait Bound Constraints
136 |
137 | | Symbol | Explanation |
138 | |--------|-------------|
139 | | `T: U` | Generic parameter `T` constrained to types that implement `U` |
140 | | `T: 'a` | Generic type `T` must outlive lifetime `'a` (meaning the type cannot transitively contain any references with lifetimes shorter than `'a`) |
141 | | `T: 'static` | Generic type `T` contains no borrowed references other than `'static` ones |
142 | | `'b: 'a` | Generic lifetime `'b` must outlive lifetime `'a` |
143 | | `T: ?Sized` | Allow generic type parameter to be a dynamically sized type |
144 | | `'a + trait`, `trait + trait` | Compound type constraint |
145 |
146 | Table B-6 shows symbols that appear in the context of calling or defining
147 | macros and specifying attributes on an item.
148 |
149 | ### Table B-6: Macros and Attributes
150 |
151 | | Symbol | Explanation |
152 | |--------|-------------|
153 | | `#[meta]` | Outer attribute |
154 | | `#![meta]` | Inner attribute |
155 | | `$ident` | Macro substitution |
156 | | `$ident:kind` | Macro capture |
157 | | `$(…)…` | Macro repetition |
158 | | `ident!(...)`, `ident!{...}`, `ident![...]` | Macro invocation |
159 |
160 | Table B-7 shows symbols that create comments.
161 |
162 | ### Table B-7: Comments
163 |
164 | | Symbol | Explanation |
165 | |--------|-------------|
166 | | `//` | Line comment |
167 | | `//!` | Inner line doc comment |
168 | | `///` | Outer line doc comment |
169 | | `/*...*/` | Block comment |
170 | | `/*!...*/` | Inner block doc comment |
171 | | `/**...*/` | Outer block doc comment |
172 |
173 | Table B-8 shows symbols that appear in the context of using tuples.
174 |
175 | ### Table B-8: Tuples
176 |
177 | | Symbol | Explanation |
178 | |--------|-------------|
179 | | `()` | Empty tuple (aka unit), both literal and type |
180 | | `(expr)` | Parenthesized expression |
181 | | `(expr,)` | Single-element tuple expression |
182 | | `(type,)` | Single-element tuple type |
183 | | `(expr, ...)` | Tuple expression |
184 | | `(type, ...)` | Tuple type |
185 | | `expr(expr, ...)` | Function call expression; also used to initialize tuple `struct`s and tuple `enum` variants |
186 | | `expr.0`, `expr.1`, etc. | Tuple indexing |
187 |
188 | Table B-9 shows the contexts in which curly braces are used.
189 |
190 | ### Table B-9: Curly Brackets
191 |
192 | | Context | Explanation |
193 | |---------|-------------|
194 | | `{...}` | Block expression |
195 | | `Type {...}` | `struct` literal |
196 |
197 | Table B-10 shows the contexts in which square brackets are used.
198 |
199 | ### Table B-10: Square Brackets
200 |
201 | | Context | Explanation |
202 | |---------|-------------|
203 | | `[...]` | Array literal |
204 | | `[expr; len]` | Array literal containing `len` copies of `expr` |
205 | | `[type; len]` | Array type containing `len` instances of `type` |
206 | | `expr[expr]` | Collection indexing. Overloadable (`Index`, `IndexMut`) |
207 | | `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]` | Collection indexing pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, or `RangeFull` as the "index" |
208 |
--------------------------------------------------------------------------------
/docs/ch19/ch19-05-macros.md:
--------------------------------------------------------------------------------
1 | # 19.5 - Macros
2 |
3 | If you're coming to Rust from C or C++, then you're no doubt already familiar with macros. We're going to give a quick introduction to macros here, but if you want to read more you should check out [The Little Book of Rust Macros](https://veykril.github.io/tlborm/introduction.html).
4 |
5 | Macros are a kind of "metaprogramming". When we write a Macro, we're actually writing Rust code that generates more Rust code.
6 |
7 | - Macros run at compile time, so they have no runtime performance impact (although they can generate code that runs at runtime, which might).
8 | - Macros can take a variable number of parameters (such as the `println!` marco does) which normal Rust functions cannot.
9 | - Macros must be brought into scope or defined locally before they are called.
10 |
11 | ## Declarative Macros with `macro_rules!` for General Metaprogramming
12 |
13 | _Declarative macros_ are sometimes called "macros by example" or just "macros" (because these are the most common kind of macro you're going to encounter). Here is a very simple macro:
14 |
15 | ```rust
16 | macro_rules! four {
17 | () => {
18 | 1 + 3
19 | };
20 | }
21 |
22 | fn main() {
23 | let x = four!();
24 | println!("{x}");
25 | }
26 |
27 | ```
28 |
29 | The `macro_rules! four` says we're going to declare a macro named `four!`. Inside the `{}`, the rest of this macro is similar to a `match` expression (in this example we only have one arm). Each rule in a `macro_rules!` is of the format `(MATCHER) => {EXPANSION};`. When we call a macro, we don't actually pass in parameters like `i32`s or `&str`s, instead we're passing in a snippet of Rust code. When the macro runs, it will try to match the passed in token tree to each matcher in turn. Once it finds a match, we'll replace the whole macro with whatever is in the expansion part.
30 |
31 | In the case of our macro above, we just have a single "empty matcher". If you were to try calling `let x = four!("hello");`, you'd get an error telling you `` no rules expected the token `"hello"` ``.
32 |
33 | A matcher can contain _captures_ which let us capture some tokens to a _metavariable_. Metavariables start with `$`:
34 |
35 | ```rust
36 | macro_rules! add_one {
37 | ($e:expr) => { $e + 1 };
38 | }
39 | ```
40 |
41 | Here if you called `add_one!(2)` would be replaced with `2 + 1`. Let's have a look at the `vec!` macro, which is a bit more exciting:
42 |
43 | ```rust
44 | #[macro_export]
45 | macro_rules! vec {
46 | ( $( $x:expr ),* ) => {
47 | {
48 | let mut temp_vec = Vec::new();
49 | $(
50 | temp_vec.push($x);
51 | )*
52 | temp_vec
53 | }
54 | };
55 | }
56 | ```
57 |
58 | :::info
59 | This is actually a slightly simplified version of `vec!`. The original tries to preallocate the correct amount of data in the new vector.
60 | :::
61 |
62 | First, notice we've added the `#[macro_export]` annotation. Without this annotation, this macro can't be used outside of the crate it is defined in.
63 |
64 | The `$(),*` part of the matcher here is called a _repetition_. These have the form `$ (...) sep rep`, where `( ... )` is the part that's being repeated, `sep` is an optional separator token, and `rep` defines how many times the pattern can repeat - `?` for zero or one, `*` for zero or more, and `+` for one or more (like in a regular expression). So `( $( $x:expr ),* )` matches zero or more expressions, separated by commas, and each time through the repetition we assign the matched part to the `$x` metavariable.
65 |
66 | On the right hand side of the `=>` we have the code we're going to expand this to. Inside the `$()` is the repetition part - this code will be inserted once for each time the repetition matches on the matcher side.
67 |
68 | So if we were to write `vec![1, 2, 3]`, at compile time this would get replaced with:
69 |
70 | ```rust
71 | {
72 | let mut temp_vec = Vec::new();
73 | temp_vec.push(1);
74 | temp_vec.push(2);
75 | temp_vec.push(3);
76 | temp_vec
77 | }
78 | ```
79 |
80 | ## Procedural Macros for Generating Code from Attributes
81 |
82 | A _procedural macro_ is a Rust function that takes in a `TokenStream` of some input source code and produces a `TokenStream` of some generated code. There are three kinds of procedural macros: custom derive, attribute-like, and function-like. When we `#[derive()]` a trait, it's going through a custom-derive macro. Procedural macros need to be defined in their own special crate for technical reasons we're going to hand wave away for this book, although this will likely change in the future.
83 |
84 | ### How to Write a Custom `derive` Macro
85 |
86 | Let's create some new projects:
87 |
88 | ```sh
89 | mkdir projects
90 | cd projects
91 | cargo new hello_macro --lib
92 | cd hello_macro
93 | cargo new hello_macro_derive --lib
94 | ```
95 |
96 | We created two projects, one inside the other. The outer project will contain our trait, and the inner wil going to contain our custom derive macro. We create these two projects one-inside-the-other because they are tightly related; if the code in the outer project changes, odds are the code in the inner project will too. Unfortunately we'll need to publish the two crates to [crates.io](https://crates.io) separately.
97 |
98 | In the outer project, we're going to create a trait:
99 |
100 | ```rust title="hello_macro/src/lib.rs"
101 | pub trait HelloMacro {
102 | fn hello_macro();
103 | }
104 | ```
105 |
106 | The idea here is that a when a consumer of our library implements this trait, we want to give them a derive macro that will implement the `hello_macro` method for them. Let's create one more project in the "projects" folder:
107 |
108 | ```sh
109 | cd ..
110 | cargo new pancakes
111 | ```
112 |
113 | And then write a file that uses our derive macro:
114 |
115 | ```rust title="pancakes/src/main.rs"
116 | use hello_macro::HelloMacro;
117 | use hello_macro_derive::HelloMacro;
118 |
119 | // This derive attribute will run our derive macro.
120 | #[derive(HelloMacro)]
121 | struct Pancakes;
122 |
123 | fn main() {
124 | // This will print "Hello, Macro! My name is Pancakes!"
125 | Pancakes::hello_macro();
126 | }
127 | ```
128 |
129 | In our inner project, we're going to add some dependencies to _Cargo.toml_:
130 |
131 | ```toml title="hello_macro/hello_macro_derive/Cargo.toml"
132 | [lib]
133 | proc-macro = true
134 |
135 | [dependencies]
136 | syn = "1.0"
137 | quote = "1.0"
138 | ```
139 |
140 | The `proc-macro = true` line [tells Cargo](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target) that this is a special library that contains procedural macros. This also gives us access to the `proc_macro` crate, which is where `TokenStream` comes from. `syn` is a crate for parsing Rust code into an [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) or _AST_, and `quote` is a crate for turning a syntax tree back into Rust code. `syn` is going to take our `Pancakes` data structure above and turn it into something like:
141 |
142 | ```rust
143 | DeriveInput {
144 | // --snip--
145 | ident: Ident {
146 | ident: "Pancakes",
147 | span: #0 bytes(95..103)
148 | },
149 | data: Struct(
150 | DataStruct {
151 | struct_token: Struct,
152 | fields: Unit,
153 | semi_token: Some(
154 | Semi
155 | )
156 | }
157 | )
158 | }
159 | ```
160 |
161 | The field we care about for our implementation is the `ident` or "identifier" for our struct. You can see what else will be passed to our macro in the [`syn::DeriveInput` documentation](https://docs.rs/syn/1.0.109/syn/struct.DeriveInput.html).
162 |
163 | Here's the code for our macro:
164 |
165 | ```rust title="hello_macro/hello_macro_derive/src/lib.rs"
166 | use proc_macro::TokenStream;
167 | use quote::quote;
168 | use syn;
169 |
170 | // This line tells Rust that this is the macro
171 | // to call when someone does `#[derive(HelloMacro)]`.
172 | #[proc_macro_derive(HelloMacro)]
173 | pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
174 | // Construct a representation of Rust code as a syntax tree
175 | // that we can manipulate
176 | let ast = syn::parse(input).unwrap();
177 |
178 | // Build the trait implementation
179 | impl_hello_macro(&ast)
180 | }
181 |
182 | // It's very common to split the derive macro into one function
183 | // that parses the input (`hello_macro_derive`) and one that
184 | // generates the code (`impl_hello_macro`).
185 | fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
186 | let name = &ast.ident;
187 |
188 | // `#name` will be replaced with `Pancakes` here.
189 | let gen = quote! {
190 | impl HelloMacro for #name {
191 | fn hello_macro() {
192 | println!("Hello, Macro! My name is {}!", stringify!(#name));
193 | }
194 | }
195 | };
196 |
197 | // Convert `gen` into a `TokenStream`.
198 | gen.into()
199 | }
200 | ```
201 |
202 | The `quote!` macro here helps us define the code we want to generate. Note the `#name` template inside of `quote!`. `quote!` has other cool template tricks, so be sure to [check out its documentation](https://docs.rs/quote/latest/quote/). The `stringify!` macro is built into rust and turns an expression like `1 + 2` into a string like `"1 + 2"`, or here `Pancakes` into `"Pancakes"`.
203 |
204 | If you want to run this, there's just one thing left to do. In our _pancakes_ project, we need to add dependencies to _Cargo.toml_ so it can find our trait and macro:
205 |
206 | ```toml title="pancakes/Cargo.toml"
207 | [dependencies]
208 | hello_macro = { path = "../hello_macro" }
209 | hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }
210 | ```
211 |
212 | Now you should be able to `cargo run` from the _pancakes_ folder. If you run into trouble, the full source is [available on GitHub](https://github.com/jwalton/rust-book-abridged/tree/master/examples/ch19-hello-macro).
213 |
214 | ### Attribute-like macros
215 |
216 | _Attribute-like_ macros are another kind of procedural macros. They let you define custom attributes, for example:
217 |
218 | ```rust
219 | #[route(GET, "/")]
220 | fn index() {
221 | ```
222 |
223 | Unlike a custom derive macro (which can only be applied to structs and enums), these can be applied to any Rust code. To define this macro, you'd create a `macro` function like this:
224 |
225 | ```rust
226 | #[proc_macro_attribute]
227 | pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
228 | // --snip--
229 | }
230 | ```
231 |
232 | The implementation would be just like the derive macro, except that there are two `TokenStream`s - one for the item we are adding this attribute to, and one for the parameters passed to the macro. Like the derive macro, this needs to be in a special crate by itself (or with other procedural macros).
233 |
234 | ### Function-like macros
235 |
236 | The last kind of procedural macro is the _function-like_ macro. The name comes from the fact that we can call them like a function, similar to `macro_rules!` macros:
237 |
238 | ```rust
239 | let sql = sql!(SELECT * FROM posts WHERE id=1);
240 | ```
241 |
242 | This macro would be defined as:
243 |
244 | ```rust
245 | #[proc_macro]
246 | pub fn sql(input: TokenStream) -> TokenStream {
247 | // --snip--
248 | }
249 | ```
250 |
--------------------------------------------------------------------------------
/docs/ch06-enums-and-pattern-matching.md:
--------------------------------------------------------------------------------
1 | # 6 - Enums and Pattern Matching
2 |
3 | ## 6.1 - Defining an Enum
4 |
5 | An _enum_ allows you to define a type by enumerating its possible _variants_. If you're coming from some other language, you probably think of an enum as basically a fancy way to assign names to a set of numbers. A Rust enum goes beyond this, as each variant of an enum can have some data associated with it, much like a struct.
6 |
7 | ```rust
8 | // Define an enum.
9 | enum IpAddrKind {
10 | V4,
11 | V6,
12 | }
13 |
14 | // Use one of the variants from the enum.
15 | let ip_address_kind = IpAddrKind::V4;
16 | ```
17 |
18 | `IpAddrKind::V4` and `IpAddrKind::V6` are both of type IpAddrKind.
19 |
20 | We can also attach data to an enum:
21 |
22 | ```rust
23 | enum Message {
24 | Quit,
25 | Move { x: i32, y: i32 },
26 | Write(String),
27 | ChangeColor(u8, u8, u8),
28 | }
29 |
30 | fn main() {
31 | let m1 = Message::Quit;
32 | let m2 = Message::Move { x: 7, y: 9 };
33 | let m3 = Message::Write(String::from("Hello"));
34 | let m4 = Message::ChangeColor(0, 255, 255);
35 | }
36 | ```
37 |
38 | Note that the different variants can take different types of associated data, and the data can either have named values like a struct or a set of values like a name tuple. Importantly though, all are of type `Message`.
39 |
40 | We can also defined methods on an enum:
41 |
42 | ```rust
43 | impl Message {
44 | fn call(&self) {
45 | // method body would be defined here
46 | }
47 | }
48 |
49 | let m = Message::Write(String::from("hello"));
50 | m.call();
51 | ```
52 |
53 | The `call` function here might use a match statement to perform different actions based on the variant of the Message enum.
54 |
55 | ### The `Option` Enum and Its Advantages Over Null Values
56 |
57 | As mentioned earlier in this book, Rust has no `null` value. In most languages, you can dereference a null pointer, and it will cause your program to crash at runtime. Rust has a strong focus on safety and makes the conscious decision to not allow null pointers to exist in the first place.
58 |
59 | However, sometimes we have a value that might not be defined. For example we might have a "middle_name" field on a User, but some users might not have a middle name. Rust handles this with the `Option` enum, defined by the standard library. `Option` is used frequently in Rust - so frequently that both `Option` and it's two variants are in the prelude, so you don't have to `use` it to bring it into scope.
60 |
61 | `Option` is defined as:
62 |
63 | ```rust
64 | enum Option {
65 | None,
66 | Some(T),
67 | }
68 | ```
69 |
70 | The `` means this is a generic enum - it can hold a value of any type. We'll talk more about generics in [chapter 10][chap10], but this is very similar to generics and template classes in other languages. When we use an `Option`, we have to specify a concrete type for `T` which defines a new type. For example, an `Option` can be `None`, or it can be `Some(i32)`.
71 |
72 | ```rust
73 | // No need for `std::Options::Some`, or even `Option::Some`,
74 | // because these are in the prelude.
75 | let some_number = Some(5);
76 | let some_str = Some("Hello");
77 |
78 | // Need to explicitly annotate type here, since Rust
79 | // can't automatically infer what type to use for
80 | // `T` from `None`.
81 | let absent_number: Option = None;
82 | ```
83 |
84 | In this example `some_number` will be of type `Option`, and `some_str` will similarly be `Option<&str>`. The `None` case here is a bit like null in a traditional language. `None` serves as a marker that a value isn't present. We're not going to be able to use use an `Option` in place of a regular `i32` though:
85 |
86 | ```rust
87 | let x = 7;
88 | let y = Some(8);
89 |
90 | // This will fail, since x and y are mismatched types
91 | let z = x + y;
92 | ```
93 |
94 | The difference between `Option` in Rust and null in other languages is that we can't just use an `Option`, we have to explicitly handle the case where the value might not be there. What we need is a way to convert an `Option` into a `T`. If you have a look at [Option in the Rust Reference](https://doc.rust-lang.org/std/option/) you'll see that it has many methods defined on it that provide different ways to extract the underlying value from an Option, each with different ways of handling the case where the value is None.
95 |
96 | ```rust
97 | let x = Some(8);
98 |
99 | // If x is Some then use the value, otherwise panic.
100 | let must_exist = x.expect("x should never be undefined here");
101 |
102 | // Same as expect, but uses a generic message.
103 | let must_exist_2 = x.unwrap();
104 |
105 | // If x is Some use the value, otherwise
106 | // if x is None use 9.
107 | let with_default = x.unwrap_or(9);
108 |
109 | // If x is Some use the value + 1, otherwise use 0.
110 | // We'll talk about match more in the next section!
111 | let from_match = match x {
112 | Some(v) => v + 1,
113 | None => 0
114 | };
115 | ```
116 |
117 | ## 6.2 The `match` Control Flow Construct
118 |
119 | `match` is a bit like a switch/case statement on steroids. Formally, a match consists of an expression, and then one or more "arms" with patterns that try to match the expression. The pattern for each arm is evaluated in order, and the code associated with the first arm that matches will be executed. The pattern side is quite a bit more flexible than a switch/case statement (see [chapter 18][chap18]). One thing to note about a match expression is that the patterns must cover every possible value - they must be _exhaustive_. If there are any possibly-unhandled-values, the compiler will error.
120 |
121 | Here's an example of a match expression, taken directly from the original Rust Book:
122 |
123 | ```rust
124 | enum Coin {
125 | Penny,
126 | Nickel,
127 | Dime,
128 | Quarter,
129 | }
130 |
131 | fn value_in_cents(coin: Coin) -> u8 {
132 | match coin {
133 | Coin::Penny => 1,
134 | Coin::Nickel => 5,
135 | Coin::Dime => 10,
136 | Coin::Quarter => 25,
137 | }
138 | }
139 | ```
140 |
141 | ### Patterns That Bind to Values
142 |
143 | A match expression can bind to parts of values that match the pattern. This can be used to extract one or more values out of an enum. We saw a quick example of this when handling `Option`s in the previous section:
144 |
145 | ```rust
146 | let x = Some(7);
147 |
148 | let from_match = match x {
149 | Some(v) => v + 1,
150 | None => 0
151 | };
152 | ```
153 |
154 | Here `v` gets bound to the contents of `Some`. Let's see this in action with our coin example from before. Let's change the Quarter variant of the Coin enum so it tells us which Canadian province this quarter is from:
155 |
156 | ```rust
157 | #[derive(Debug)] // so we can inspect the state in a minute
158 | enum Province {
159 | Alberta,
160 | BritishColumbia,
161 | // --snip--
162 | }
163 |
164 | enum Coin {
165 | Penny,
166 | Nickel,
167 | Dime,
168 | Quarter(Province),
169 | Loonie,
170 | Toonie,
171 | }
172 |
173 | fn value_in_cents(coin: Coin) -> u8 {
174 | match coin {
175 | Coin::Penny => 1,
176 | Coin::Nickel => 5,
177 | Coin::Dime => 10,
178 | Coin::Quarter(province) => {
179 | println!("Quarter from {:?}!", province);
180 | 25
181 | }
182 | Loonie => 100,
183 | Toonie => 200,
184 | }
185 | }
186 | ```
187 |
188 | Each arm of the match can have a simple expression, or a block of code. As with functions, if the block ends with an expression this will be used as the value for that arm. If we were to call this with a `Coin::Quarter(Province::Ontario)`, then in the Quarter arm of the match, `province` would be bound to `Province::Ontario`.
189 |
190 | Let's take a moment here to reflect on ownership implications. In this case, the Province enum implements the Copy trait, so we don't have to worry about ownership as the Province enum is going to be allocated on the stack. If we change the Coin enum so it is `Quarter(String)` however, then binding `province` inside the match would move ownership of the String out of the coin and we wouldn't be able to use it again outside the match! We could fix this by borrowing the value instead, either by changing the match expression to `match &coin` or to make `value_in_cents` take a reference to the Coin as a parameter instead of the Coin itself.
191 |
192 | ### Catch-all Patterns and the \_ Placeholder
193 |
194 | A match expression must be exhaustive - it has to cover all possible cases. Sometimes we have a number of cases we want to treat the same way, or enumerating all cases would be impractical. If we wrote a match and passed in an `i32` as the expression, we certainly wouldn't want to write out all 4 billion possible values the i32 could be! The catch-all pattern lets us create a default arm (similar to `default` in a switch/case statement in many languages).
195 |
196 | The example used by the original Rust Book is that you're building a board game where a player rolls a dice. On a roll of a 3, the place gets a hat. On a 7, the player loses their hat. On any other dice roll, they move that many spaces:
197 |
198 | ```rust
199 | let dice_roll = 9;
200 | match dice_roll {
201 | 3 => add_fancy_hat(),
202 | 7 => remove_fancy_hat(),
203 | other => move_player(other),
204 | }
205 | ```
206 |
207 | Here we have explicit arms for the 3 and 7 case, and then we have a catch-all pattern that binds the value of `dice_roll` to `other`. If we didn't actually want to _use_ the value in the catch-all case, we wouldn't want to bind the value to a variable, since we'd get a warning from the compiler about an unused variable. In this case, we can replace `other` with `_`:
208 |
209 | ```rust
210 | match dice_roll {
211 | 3 => add_fancy_hat(),
212 | 7 => remove_fancy_hat(),
213 | _ => (),
214 | }
215 | ```
216 |
217 | Here we're making this arm evaluate to the empty unit tuple, explicitly telling Rust that we don't want to do anything in this case. (Note that unlike `other`, `_` also doesn't bind the variable, which has ownership implications! See [chapter 18](./ch18-patterns-and-matching.md#ignoring-an-unused-variable-by-starting-its-name-with-_).
218 |
219 | ## 6.3 - Concise Control Flow with `if let`
220 |
221 | On other languages you can convert a switch/case statement into a series of if/else statements. You can do the same in Rust. You could write:
222 |
223 | ```rust
224 | let config_max = Some(3u8);
225 | match config_max {
226 | Some(max) => println!("The maximum is configured to be {}", max),
227 | _ => (),
228 | }
229 | ```
230 |
231 | But this is a bit verbose, considering the default arm does nothing. We can rewrite this as an if statement with `if let`:
232 |
233 | ```rust
234 | let config_max = Some(3u8);
235 | if let Some(max) = config_max {
236 | println!("The maximum is configured to be {}", max);
237 | }
238 | ```
239 |
240 | `if let` takes a pattern and an expression, separated by an equals sign, and works exactly like the arm of a switch. The downside to `if let` over a `match` statement is that the compiler does not force you to exhaustively handle every possible scenario.
241 |
242 | Continue to [chapter 7][chap7].
243 |
244 | [chap7]: ./ch07-packages-crates-modules.md "Chapter 7: Managing Growing Projects with Packages, Crates, and Modules"
245 | [chap10]: ./ch10/ch10-01-generic-data-types.md "Chapter 10: Generic Types, Traits, and Lifetimes"
246 | [chap18]: ./ch18-patterns-and-matching.md "Chapter 18: Patterns and Matching"
247 |
--------------------------------------------------------------------------------
/static/img/undraw_docusaurus_tree.svg:
--------------------------------------------------------------------------------
1 |
41 |
--------------------------------------------------------------------------------
/docs/ch21-async.md:
--------------------------------------------------------------------------------
1 | # 21 - Async Programming
2 |
3 | In this section we're going to re-implement our web server from [chapter 20][chap20] using async functions. We're just going to give you enough here to get your feet wet. For further reading, check out [Asynchronous Programming in Rust](https://rust-lang.github.io/async-book/), and the [Tokio Tutorial](https://tokio.rs/tokio/tutorial). As usual, if you're looking for the full source for this project, it's [in the GitHub repo](https://github.com/jwalton/rust-book-abridged/tree/master/examples/ch21-async-web-server).
4 |
5 | ## JavaScript
6 |
7 | Wait... Isn't this supposed to be a book about Rust? It is, but we're going to start this chapter off talking about JavaScript. Love it or hate it, JavaScript is the most popular language in the world, and it is probably where most people were first exposed to the idea of async programming.
8 |
9 | ```js title="user.js"
10 | // JavaScript Code
11 | import * as fs from "fs/promises";
12 |
13 | async function getUserName() {
14 | const username = await fs.readFile("./username.txt", { encoding: "utf-8" });
15 | console.log(`Hello ${username}`);
16 | }
17 | ```
18 |
19 | Even if you don't know JavaScript, hopefully this example is simple enough that you can follow along. We're calling `fs.readFile` to read in a file. In JavaScript this is going to return a `Promise`. A `Promise` in JavaScript is the result of some calculation we don't know yet (similar to a `Future` in Java, or as we'll see in a moment a `Future` in Rust). The magic in this function happens at the `await` keyword. When we `await` a promise, the current function stops executing, allowing other functions to run. At some future point in time when the promise resolves, this function will continue from where it left off.
20 |
21 | In JavaScript, the above is actually more or less syntactic sugar for:
22 |
23 | ```js title="user.js"
24 | // JavaScript Code
25 | import * as fs from 'fs/promises';
26 |
27 | function getUserName() {
28 | return fs.readFile("./username.txt", { encoding: 'utf-8' })
29 | .then(username => console.log(`Hello ${username}`));
30 | ```
31 |
32 | Here it's a little easier to understand how the execution of the function can be suspended. `getUserName` calls into `readFile` which creates a promise, and then `getUserName` returns. At some future point in time, when the promise resolves, someone will call into the closure we're passing to `then`. Running this closure is how we "continue" this function in JavaScript.
33 |
34 | In Rust, we could rewrite the above example as something like:
35 |
36 | ```rust
37 | use std::{error::Error};
38 | use tokio::fs;
39 |
40 | async fn get_user_name() -> Result<(), Box> {
41 | let username = fs::read_to_string("./username.txt").await?;
42 | println!("Hello {username}");
43 |
44 | Ok(())
45 | }
46 |
47 | ```
48 |
49 | This is very similar to the JavaScript example in many ways. Here `fs::read_to_string` returns a type that implements the `Future` trait (specifically `Future