mirror of https://github.com/rust-lang/book
anchors on listings, figures & tables added
This commit is contained in:
parent
105e252de6
commit
05d3c50279
|
@ -11,6 +11,9 @@ appear in context, a short explanation, and whether that operator is
|
|||
overloadable. If an operator is overloadable, the relevant trait to use to
|
||||
overload that operator is listed.
|
||||
|
||||
[Table-B-1]: #Table-B-1
|
||||
<a name="Table-B-1"></a>
|
||||
|
||||
<span class="caption">Table B-1: Operators</span>
|
||||
|
||||
| Operator | Example | Explanation | Overloadable? |
|
||||
|
@ -77,6 +80,9 @@ that is, they don’t behave like a function or method call.
|
|||
Table B-2 shows symbols that appear on their own and are valid in a variety of
|
||||
locations.
|
||||
|
||||
[Table-B-2]: #Table-B-2
|
||||
<a name="Table-B-2"></a>
|
||||
|
||||
<span class="caption">Table B-2: Stand-Alone Syntax</span>
|
||||
|
||||
| Symbol | Explanation |
|
||||
|
@ -96,6 +102,9 @@ locations.
|
|||
Table B-3 shows symbols that appear in the context of a path through the module
|
||||
hierarchy to an item.
|
||||
|
||||
[Table-B-3]: #Table-B-3
|
||||
<a name="Table-B-3"></a>
|
||||
|
||||
<span class="caption">Table B-3: Path-Related Syntax</span>
|
||||
|
||||
| Symbol | Explanation |
|
||||
|
@ -113,6 +122,9 @@ hierarchy to an item.
|
|||
Table B-4 shows symbols that appear in the context of using generic type
|
||||
parameters.
|
||||
|
||||
[Table-B-4]: #Table-B-4
|
||||
<a name="Table-B-4"></a>
|
||||
|
||||
<span class="caption">Table B-4: Generics</span>
|
||||
|
||||
| Symbol | Explanation |
|
||||
|
@ -129,6 +141,9 @@ parameters.
|
|||
Table B-5 shows symbols that appear in the context of constraining generic type
|
||||
parameters with trait bounds.
|
||||
|
||||
[Table-B-5]: #Table-B-5
|
||||
<a name="Table-B-5"></a>
|
||||
|
||||
<span class="caption">Table B-5: Trait Bound Constraints</span>
|
||||
|
||||
| Symbol | Explanation |
|
||||
|
@ -143,6 +158,9 @@ parameters with trait bounds.
|
|||
Table B-6 shows symbols that appear in the context of calling or defining
|
||||
macros and specifying attributes on an item.
|
||||
|
||||
[Table-B-6]: #Table-B-6
|
||||
<a name="Table-B-6"></a>
|
||||
|
||||
<span class="caption">Table B-6: Macros and Attributes</span>
|
||||
|
||||
| Symbol | Explanation |
|
||||
|
@ -155,6 +173,9 @@ macros and specifying attributes on an item.
|
|||
|
||||
Table B-7 shows symbols that create comments.
|
||||
|
||||
[Table-B-7]: #Table-B-7
|
||||
<a name="Table-B-7"></a>
|
||||
|
||||
<span class="caption">Table B-7: Comments</span>
|
||||
|
||||
| Symbol | Explanation |
|
||||
|
@ -168,6 +189,9 @@ Table B-7 shows symbols that create comments.
|
|||
|
||||
Table B-8 shows symbols that appear in the context of using tuples.
|
||||
|
||||
[Table-B-8]: #Table-B-8
|
||||
<a name="Table-B-8"></a>
|
||||
|
||||
<span class="caption">Table B-8: Tuples</span>
|
||||
|
||||
| Symbol | Explanation |
|
||||
|
@ -184,6 +208,9 @@ Table B-8 shows symbols that appear in the context of using tuples.
|
|||
|
||||
Table B-9 shows the contexts in which curly braces are used.
|
||||
|
||||
[Table-B-9]: #Table-B-9
|
||||
<a name="Table-B-9"></a>
|
||||
|
||||
<span class="caption">Table B-9: Curly Brackets</span>
|
||||
|
||||
| Context | Explanation |
|
||||
|
@ -193,6 +220,9 @@ Table B-9 shows the contexts in which curly braces are used.
|
|||
|
||||
Table B-10 shows the contexts in which square brackets are used.
|
||||
|
||||
[Table-B-10]: #Table-B-10
|
||||
<a name="Table-B-10"></a>
|
||||
|
||||
<span class="caption">Table B-10: Square Brackets</span>
|
||||
|
||||
| Context | Explanation |
|
||||
|
|
|
@ -93,8 +93,10 @@ We could also use the `vec!` macro to make a vector of two integers or a vector
|
|||
of five string slices. We wouldn’t be able to use a function to do the same
|
||||
because we wouldn’t know the number or type of values up front.
|
||||
|
||||
Let’s look at a slightly simplified definition of the `vec!` macro in Listing
|
||||
D-1.
|
||||
Let’s look at a slightly simplified definition of the `vec!` macro in Listing D-1.
|
||||
|
||||
[Listing-D-1]: #Listing-D-1
|
||||
<a name="Listing-D-1"></a>
|
||||
|
||||
```rust
|
||||
#[macro_export]
|
||||
|
@ -202,6 +204,9 @@ programmer to write code like Listing D-2 using our crate.
|
|||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-D-2]: #Listing-D-2
|
||||
<a name="Listing-D-2"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate hello_macro;
|
||||
#[macro_use]
|
||||
|
@ -311,6 +316,9 @@ compile until we add a definition for the `impl_hello_macro` function.
|
|||
|
||||
<span class="filename">Filename: hello_macro_derive/src/lib.rs</span>
|
||||
|
||||
[Listing-D-3]: #Listing-D-3
|
||||
<a name="Listing-D-3"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate proc_macro;
|
||||
extern crate syn;
|
||||
|
|
|
@ -56,10 +56,13 @@ the *.rs* extension. If you’re using more than one word in your filename, use
|
|||
an underscore to separate them. For example, use *hello_world.rs* rather than
|
||||
*helloworld.rs*.
|
||||
|
||||
Now open the *main.rs* file you just created and enter the code in Listing 1-1.
|
||||
Now open the *main.rs* file you just created and enter the code in [Listing 1-1][Listing-1-1].
|
||||
|
||||
<span class="filename">Filename: main.rs</span>
|
||||
|
||||
[Listing-1-1]: #Listing-1-1
|
||||
<a name="Listing-1-1"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
|
@ -200,3 +203,5 @@ Just compiling with `rustc` is fine for simple programs, but as your project
|
|||
grows, you’ll want to manage all the options and make it easy to share your
|
||||
code. Next, we’ll introduce you to the Cargo tool, which will help you write
|
||||
real-world Rust programs.
|
||||
|
||||
[Listing-1-1]: ch01-02-hello-world.html#Listing-1-1
|
||||
|
|
|
@ -52,10 +52,13 @@ repository along with a *.gitignore* file.
|
|||
> the `--vcs` flag. Run `cargo new --help` to see the available options.
|
||||
|
||||
Open *Cargo.toml* in your text editor of choice. It should look similar to the
|
||||
code in Listing 1-2.
|
||||
code in [Listing 1-2][Listing-1-2].
|
||||
|
||||
<span class="filename">Filename: Cargo.toml</span>
|
||||
|
||||
[Listing-1-2]: #Listing-1-2
|
||||
<a name="Listing-1-2"></a>
|
||||
|
||||
```toml
|
||||
[package]
|
||||
name = "hello_cargo"
|
||||
|
@ -98,7 +101,7 @@ fn main() {
|
|||
```
|
||||
|
||||
Cargo has generated a Hello, world! program for you, just like the one we wrote
|
||||
in Listing 1-1! So far, the differences between our previous project and the
|
||||
in [Listing 1-1][Listing-1-1]! So far, the differences between our previous project and the
|
||||
project Cargo generates are that Cargo placed the code in the *src* directory,
|
||||
and we have a *Cargo.toml* configuration file in the top directory.
|
||||
|
||||
|
@ -242,3 +245,6 @@ This is a great time to build a more substantial program to get used to reading
|
|||
and writing Rust code. So, in Chapter 2, we’ll build a guessing game program.
|
||||
If you would rather start by learning how common programming concepts work in
|
||||
Rust, see Chapter 3 and then return to Chapter 2.
|
||||
|
||||
[Listing-1-1]: ch01-02-hello-world.html#Listing-1-1
|
||||
[Listing-1-2]: ch01-03-hello-cargo.html#Listing-1-2
|
||||
|
|
|
@ -75,11 +75,14 @@ Reopen the *src/main.rs* file. You’ll be writing all the code in this file.
|
|||
|
||||
The first part of the guessing game program will ask for user input, process
|
||||
that input, and check that the input is in the expected form. To start, we’ll
|
||||
allow the player to input a guess. Enter the code in Listing 2-1 into
|
||||
allow the player to input a guess. Enter the code in [Listing 2-1][Listing-2-1] into
|
||||
*src/main.rs*.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-2-1]: #Listing-2-1
|
||||
<a name="Listing-2-1"></a>
|
||||
|
||||
```rust,ignore
|
||||
use std::io;
|
||||
|
||||
|
@ -392,7 +395,10 @@ version 0.3.14.”
|
|||
[semver]: http://semver.org
|
||||
|
||||
Now, without changing any of the code, let’s build the project, as shown in
|
||||
Listing 2-2.
|
||||
[Listing 2-2][Listing-2-2].
|
||||
|
||||
[Listing-2-2]: #Listing-2-2
|
||||
<a name="Listing-2-2"></a>
|
||||
|
||||
```text
|
||||
$ cargo build
|
||||
|
@ -509,10 +515,13 @@ from a number of packages.
|
|||
### Generating a Random Number
|
||||
|
||||
Now that you’ve added the `rand` crate to *Cargo.toml*, let’s start using
|
||||
`rand`. The next step is to update *src/main.rs*, as shown in Listing 2-3.
|
||||
`rand`. The next step is to update *src/main.rs*, as shown in [Listing 2-3][Listing-2-3].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-2-3]: #Listing-2-3
|
||||
<a name="Listing-2-3"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate rand;
|
||||
|
||||
|
@ -598,11 +607,14 @@ You should get different random numbers, and they should all be numbers between
|
|||
## Comparing the Guess to the Secret Number
|
||||
|
||||
Now that we have user input and a random number, we can compare them. That step
|
||||
is shown in Listing 2-4. Note that this code won’t compile quite yet, as we
|
||||
is shown in [Listing 2-4][Listing-2-4]. Note that this code won’t compile quite yet, as we
|
||||
will explain.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-2-4]: #Listing-2-4
|
||||
<a name="Listing-2-4"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate rand;
|
||||
|
||||
|
@ -664,7 +676,7 @@ the code in that arm and moves to the next arm. The next arm’s pattern,
|
|||
that arm will execute and print `Too big!` to the screen. The `match`
|
||||
expression ends because it has no need to look at the last arm in this scenario.
|
||||
|
||||
However, the code in Listing 2-4 won’t compile yet. Let’s try it:
|
||||
However, the code in [Listing 2-4][Listing-2-4] won’t compile yet. Let’s try it:
|
||||
|
||||
```text
|
||||
$ cargo build
|
||||
|
@ -893,10 +905,13 @@ exiting the program, because the loop is the last part of `main`.
|
|||
To further refine the game’s behavior, rather than crashing the program when
|
||||
the user inputs a non-number, let’s make the game ignore a non-number so the
|
||||
user can continue guessing. We can do that by altering the line where `guess`
|
||||
is converted from a `String` to a `u32`, as shown in Listing 2-5.
|
||||
is converted from a `String` to a `u32`, as shown in [Listing 2-5][Listing-2-5].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-2-5]: #Listing-2-5
|
||||
<a name="Listing-2-5"></a>
|
||||
|
||||
```rust,ignore
|
||||
// --snip--
|
||||
|
||||
|
@ -965,10 +980,13 @@ You win!
|
|||
Awesome! With one tiny final tweak, we will finish the guessing game. Recall
|
||||
that the program is still printing the secret number. That worked well for
|
||||
testing, but it ruins the game. Let’s delete the `println!` that outputs the
|
||||
secret number. Listing 2-6 shows the final code.
|
||||
secret number. [Listing 2-6][Listing-2-6] shows the final code.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-2-6]: #Listing-2-6
|
||||
<a name="Listing-2-6"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate rand;
|
||||
|
||||
|
@ -1022,3 +1040,10 @@ variables, data types, and functions, and shows how to use them in Rust.
|
|||
Chapter 4 explores ownership, a feature that makes Rust different from other
|
||||
languages. Chapter 5 discusses structs and method syntax, and Chapter 6
|
||||
explains how enums work.
|
||||
|
||||
[Listing-2-1]: ch02-00-guessing-game-tutorial.html#Listing-2-1
|
||||
[Listing-2-2]: ch02-00-guessing-game-tutorial.html#Listing-2-2
|
||||
[Listing-2-3]: ch02-00-guessing-game-tutorial.html#Listing-2-3
|
||||
[Listing-2-4]: ch02-00-guessing-game-tutorial.html#Listing-2-4
|
||||
[Listing-2-5]: ch02-00-guessing-game-tutorial.html#Listing-2-5
|
||||
[Listing-2-6]: ch02-00-guessing-game-tutorial.html#Listing-2-6
|
||||
|
|
|
@ -43,11 +43,14 @@ these from other programming languages. Let’s jump into how they work in Rust.
|
|||
An *integer* is a number without a fractional component. We used one integer
|
||||
type in Chapter 2, the `u32` type. This type declaration indicates that the
|
||||
value it’s associated with should be an unsigned integer (signed integer types
|
||||
start with `i`, instead of `u`) that takes up 32 bits of space. Table 3-1 shows
|
||||
start with `i`, instead of `u`) that takes up 32 bits of space. [Table 3-1][Table-3-1] shows
|
||||
the built-in integer types in Rust. Each variant in the Signed and Unsigned
|
||||
columns (for example, `i16`) can be used to declare the type of an integer
|
||||
value.
|
||||
|
||||
[Table-3-1]: #Table-3-1
|
||||
<a name="Table-3-1"></a>
|
||||
|
||||
<span class="caption">Table 3-1: Integer Types in Rust</span>
|
||||
|
||||
| Length | Signed | Unsigned |
|
||||
|
@ -79,10 +82,13 @@ Additionally, the `isize` and `usize` types depend on the kind of computer your
|
|||
program is running on: 64 bits if you’re on a 64-bit architecture and 32 bits
|
||||
if you’re on a 32-bit architecture.
|
||||
|
||||
You can write integer literals in any of the forms shown in Table 3-2. Note
|
||||
You can write integer literals in any of the forms shown in [Table 3-2][Table-3-2]. Note
|
||||
that all number literals except the byte literal allow a type suffix, such as
|
||||
`57u8`, and `_` as a visual separator, such as `1_000`.
|
||||
|
||||
[Table-3-2]: #Table-3-2
|
||||
<a name="Table-3-2"></a>
|
||||
|
||||
<span class="caption">Table 3-2: Integer Literals in Rust</span>
|
||||
|
||||
| Number literals | Example |
|
||||
|
@ -362,3 +368,6 @@ low-level languages, this kind of check is not done, and when you provide an
|
|||
incorrect index, invalid memory can be accessed. Rust protects you against this
|
||||
kind of error by immediately exiting instead of allowing the memory access and
|
||||
continuing. Chapter 9 discusses more of Rust’s error handling.
|
||||
|
||||
[Table-3-1]: ch03-02-data-types.html#Table-3-1
|
||||
[Table-3-2]: ch03-02-data-types.html#Table-3-2
|
||||
|
|
|
@ -148,10 +148,13 @@ instructions that perform some action and do not return a value. *Expressions*
|
|||
evaluate to a resulting value. Let’s look at some examples.
|
||||
|
||||
Creating a variable and assigning a value to it with the `let` keyword is a
|
||||
statement. In Listing 3-1, `let y = 6;` is a statement.
|
||||
statement. In [Listing 3-1][Listing-3-1], `let y = 6;` is a statement.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-3-1]: #Listing-3-1
|
||||
<a name="Listing-3-1"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let y = 6;
|
||||
|
@ -197,7 +200,7 @@ languages, you can write `x = y = 6` and have both `x` and `y` have the value
|
|||
Expressions evaluate to something and make up most of the rest of the code that
|
||||
you’ll write in Rust. Consider a simple math operation, such as `5 + 6`, which
|
||||
is an expression that evaluates to the value `11`. Expressions can be part of
|
||||
statements: in Listing 3-1, the `6` in the statement `let y = 6;` is an
|
||||
statements: in [Listing 3-1][Listing-3-1], the `6` in the statement `let y = 6;` is an
|
||||
expression that evaluates to the value `6`. Calling a function is an
|
||||
expression. Calling a macro is an expression. The block that we use to create
|
||||
new scopes, `{}`, is an expression, for example:
|
||||
|
@ -342,3 +345,5 @@ the empty tuple. Therefore, nothing is returned, which contradicts the function
|
|||
definition and results in an error. In this output, Rust provides a message to
|
||||
possibly help rectify this issue: it suggests removing the semicolon, which
|
||||
would fix the error.
|
||||
|
||||
[Listing-3-1]: ch03-03-how-functions-work.html#Listing-3-1
|
||||
|
|
|
@ -172,10 +172,13 @@ Rust branching construct called `match` for these cases.
|
|||
#### Using `if` in a `let` Statement
|
||||
|
||||
Because `if` is an expression, we can use it on the right side of a `let`
|
||||
statement, as in Listing 3-2.
|
||||
statement, as in [Listing 3-2][Listing-3-2].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-3-2]: #Listing-3-2
|
||||
<a name="Listing-3-2"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let condition = true;
|
||||
|
@ -207,7 +210,7 @@ Remember that blocks of code evaluate to the last expression in them, and
|
|||
numbers by themselves are also expressions. In this case, the value of the
|
||||
whole `if` expression depends on which block of code executes. This means the
|
||||
values that have the potential to be results from each arm of the `if` must be
|
||||
the same type; in Listing 3-2, the results of both the `if` arm and the `else`
|
||||
the same type; in [Listing 3-2][Listing-3-2], the results of both the `if` arm and the `else`
|
||||
arm were `i32` integers. If the types are mismatched, as in the following
|
||||
example, we’ll get an error:
|
||||
|
||||
|
@ -319,12 +322,15 @@ using a combination of `loop`, `if`, `else`, and `break`; you could try that
|
|||
now in a program, if you’d like.
|
||||
|
||||
However, this pattern is so common that Rust has a built-in language construct
|
||||
for it, called a `while` loop. Listing 3-3 uses `while`: the program loops
|
||||
for it, called a `while` loop. [Listing 3-3][Listing-3-3] uses `while`: the program loops
|
||||
three times, counting down each time, and then, after the loop, it prints
|
||||
another message and exits.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-3-3]: #Listing-3-3
|
||||
<a name="Listing-3-3"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let mut number = 3;
|
||||
|
@ -349,10 +355,13 @@ true, the code runs; otherwise, it exits the loop.
|
|||
#### Looping Through a Collection with `for`
|
||||
|
||||
You could use the `while` construct to loop over the elements of a collection,
|
||||
such as an array. For example, let’s look at Listing 3-4.
|
||||
such as an array. For example, let’s look at [Listing 3-4][Listing-3-4].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-3-4]: #Listing-3-4
|
||||
<a name="Listing-3-4"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let a = [10, 20, 30, 40, 50];
|
||||
|
@ -396,10 +405,13 @@ code to perform the conditional check on every element on every iteration
|
|||
through the loop.
|
||||
|
||||
As a more concise alternative, you can use a `for` loop and execute some code
|
||||
for each item in a collection. A `for` loop looks like the code in Listing 3-5.
|
||||
for each item in a collection. A `for` loop looks like the code in [Listing 3-5][Listing-3-5].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-3-5]: #Listing-3-5
|
||||
<a name="Listing-3-5"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let a = [10, 20, 30, 40, 50];
|
||||
|
@ -413,12 +425,12 @@ fn main() {
|
|||
<span class="caption">Listing 3-5: Looping through each element of a collection
|
||||
using a `for` loop</span>
|
||||
|
||||
When we run this code, we’ll see the same output as in Listing 3-4. More
|
||||
When we run this code, we’ll see the same output as in [Listing 3-4][Listing-3-4]. More
|
||||
importantly, we’ve now increased the safety of the code and eliminated the
|
||||
chance of bugs that might result from going beyond the end of the array or not
|
||||
going far enough and missing some items.
|
||||
|
||||
For example, in the code in Listing 3-4, if you removed an item from the `a`
|
||||
For example, in the code in [Listing 3-4][Listing-3-4], if you removed an item from the `a`
|
||||
array but forgot to update the condition to `while index < 4`, the code would
|
||||
panic. Using the `for` loop, you wouldn’t need to remember to change any other
|
||||
code if you changed the number of values in the array.
|
||||
|
@ -426,7 +438,7 @@ code if you changed the number of values in the array.
|
|||
The safety and conciseness of `for` loops make them the most commonly used loop
|
||||
construct in Rust. Even in situations in which you want to run some code a
|
||||
certain number of times, as in the countdown example that used a `while` loop
|
||||
in Listing 3-3, most Rustaceans would use a `for` loop. The way to do that
|
||||
in [Listing 3-3][Listing-3-3], most Rustaceans would use a `for` loop. The way to do that
|
||||
would be to use a `Range`, which is a type provided by the standard library
|
||||
that generates all numbers in sequence starting from one number and ending
|
||||
before another number.
|
||||
|
@ -461,3 +473,8 @@ programs to do the following:
|
|||
|
||||
When you’re ready to move on, we’ll talk about a concept in Rust that *doesn’t*
|
||||
commonly exist in other programming languages: ownership.
|
||||
|
||||
[Listing-3-2]: ch03-05-control-flow.html#Listing-3-2
|
||||
[Listing-3-3]: ch03-05-control-flow.html#Listing-3-3
|
||||
[Listing-3-4]: ch03-05-control-flow.html#Listing-3-4
|
||||
[Listing-3-5]: ch03-05-control-flow.html#Listing-3-5
|
||||
|
|
|
@ -110,9 +110,12 @@ let s = "hello";
|
|||
|
||||
The variable `s` refers to a string literal, where the value of the string is
|
||||
hardcoded into the text of our program. The variable is valid from the point at
|
||||
which it’s declared until the end of the current *scope*. Listing 4-1 has
|
||||
which it’s declared until the end of the current *scope*. [Listing 4-1][Listing-4-1] has
|
||||
comments annotating where the variable `s` is valid.
|
||||
|
||||
[Listing-4-1]: #Listing-4-1
|
||||
<a name="Listing-4-1"></a>
|
||||
|
||||
```rust
|
||||
{ // s is not valid here, it’s not yet declared
|
||||
let s = "hello"; // s is valid from this point forward
|
||||
|
@ -211,7 +214,7 @@ We need to pair exactly one `allocate` with exactly one `free`.
|
|||
|
||||
Rust takes a different path: the memory is automatically returned once the
|
||||
variable that owns it goes out of scope. Here’s a version of our scope example
|
||||
from Listing 4-1 using a `String` instead of a string literal:
|
||||
from [Listing 4-1][Listing-4-1] using a `String` instead of a string literal:
|
||||
|
||||
```rust
|
||||
{
|
||||
|
@ -241,7 +244,10 @@ we’ve allocated on the heap. Let’s explore some of those situations now.
|
|||
#### Ways Variables and Data Interact: Move
|
||||
|
||||
Multiple variables can interact with the same data in different ways in Rust.
|
||||
Let’s look at an example using an integer in Listing 4-2.
|
||||
Let’s look at an example using an integer in [Listing 4-2][Listing-4-2].
|
||||
|
||||
[Listing-4-2]: #Listing-4-2
|
||||
<a name="Listing-4-2"></a>
|
||||
|
||||
```rust
|
||||
let x = 5;
|
||||
|
@ -268,12 +274,15 @@ This looks very similar to the previous code, so we might assume that the way
|
|||
it works would be the same: that is, the second line would make a copy of the
|
||||
value in `s1` and bind it to `s2`. But this isn’t quite what happens.
|
||||
|
||||
Take a look at Figure 4-1 to see what is happening to `String` under the
|
||||
Take a look at [Figure 4-1][Figure-4-1] to see what is happening to `String` under the
|
||||
covers. A `String` is made up of three parts, shown on the left: a pointer to
|
||||
the memory that holds the contents of the string, a length, and a capacity.
|
||||
This group of data is stored on the stack. On the right is the memory on the
|
||||
heap that holds the contents.
|
||||
|
||||
[Figure-4-1]: #Figure-4-1
|
||||
<a name="Figure-4-1"></a>
|
||||
|
||||
<img alt="String in memory" src="img/trpl04-01.svg" class="center" style="width: 50%;" />
|
||||
|
||||
<span class="caption">Figure 4-1: Representation in memory of a `String`
|
||||
|
@ -288,18 +297,24 @@ the capacity.
|
|||
When we assign `s1` to `s2`, the `String` data is copied, meaning we copy the
|
||||
pointer, the length, and the capacity that are on the stack. We do not copy the
|
||||
data on the heap that the pointer refers to. In other words, the data
|
||||
representation in memory looks like Figure 4-2.
|
||||
representation in memory looks like [Figure 4-2][Figure-4-2].
|
||||
|
||||
[Figure-4-2]: #Figure-4-2
|
||||
<a name="Figure-4-2"></a>
|
||||
|
||||
<img alt="s1 and s2 pointing to the same value" src="img/trpl04-02.svg" class="center" style="width: 50%;" />
|
||||
|
||||
<span class="caption">Figure 4-2: Representation in memory of the variable `s2`
|
||||
that has a copy of the pointer, length, and capacity of `s1`</span>
|
||||
|
||||
The representation does *not* look like Figure 4-3, which is what memory would
|
||||
The representation does *not* look like [Figure 4-3][Figure-4-3], which is what memory would
|
||||
look like if Rust instead copied the heap data as well. If Rust did this, the
|
||||
operation `s2 = s1` could be very expensive in terms of runtime performance if
|
||||
the data on the heap were large.
|
||||
|
||||
[Figure-4-3]: #Figure-4-3
|
||||
<a name="Figure-4-3"></a>
|
||||
|
||||
<img alt="s1 and s2 to two places" src="img/trpl04-03.svg" class="center" style="width: 50%;" />
|
||||
|
||||
<span class="caption">Figure 4-3: Another possibility for what `s2 = s1` might
|
||||
|
@ -307,7 +322,7 @@ do if Rust copied the heap data as well</span>
|
|||
|
||||
Earlier, we said that when a variable goes out of scope, Rust automatically
|
||||
calls the `drop` function and cleans up the heap memory for that variable. But
|
||||
Figure 4-2 shows both data pointers pointing to the same location. This is a
|
||||
[Figure 4-2][Figure-4-2] shows both data pointers pointing to the same location. This is a
|
||||
problem: when `s2` and `s1` go out of scope, they will both try to free the
|
||||
same memory. This is known as a *double free* error and is one of the memory
|
||||
safety bugs we mentioned previously. Freeing memory twice can lead to memory
|
||||
|
@ -348,7 +363,10 @@ other languages, the concept of copying the pointer, length, and capacity
|
|||
without copying the data probably sounds like making a shallow copy. But
|
||||
because Rust also invalidates the first variable, instead of being called a
|
||||
shallow copy, it’s known as a *move*. In this example, we would say that `s1`
|
||||
was *moved* into `s2`. So what actually happens is shown in Figure 4-4.
|
||||
was *moved* into `s2`. So what actually happens is shown in [Figure 4-4][Figure-4-4].
|
||||
|
||||
[Figure-4-4]: #Figure-4-4
|
||||
<a name="Figure-4-4"></a>
|
||||
|
||||
<img alt="s1 moved to s2" src="img/trpl04-04.svg" class="center" style="width: 50%;" />
|
||||
|
||||
|
@ -378,7 +396,7 @@ let s2 = s1.clone();
|
|||
println!("s1 = {}, s2 = {}", s1, s2);
|
||||
```
|
||||
|
||||
This works just fine and explicitly produces the behavior shown in Figure 4-3,
|
||||
This works just fine and explicitly produces the behavior shown in [Figure 4-3][Figure-4-3],
|
||||
where the heap data *does* get copied.
|
||||
|
||||
When you see a call to `clone`, you know that some arbitrary code is being
|
||||
|
@ -388,7 +406,7 @@ different is going on.
|
|||
#### Stack-Only Data: Copy
|
||||
|
||||
There’s another wrinkle we haven’t talked about yet. This code using integers,
|
||||
part of which was shown in Listing 4-2, works and is valid:
|
||||
part of which was shown in [Listing 4-2][Listing-4-2], works and is valid:
|
||||
|
||||
```rust
|
||||
let x = 5;
|
||||
|
@ -433,11 +451,14 @@ be sure, but as a general rule, any group of simple scalar values can be
|
|||
|
||||
The semantics for passing a value to a function are similar to those for
|
||||
assigning a value to a variable. Passing a variable to a function will move or
|
||||
copy, just as assignment does. Listing 4-3 has an example with some annotations
|
||||
copy, just as assignment does. [Listing 4-3][Listing-4-3] has an example with some annotations
|
||||
showing where variables go into and out of scope.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-4-3]: #Listing-4-3
|
||||
<a name="Listing-4-3"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let s = String::from("hello"); // s comes into scope
|
||||
|
@ -474,11 +495,14 @@ the ownership rules prevent you from doing so.
|
|||
|
||||
### Return Values and Scope
|
||||
|
||||
Returning values can also transfer ownership. Listing 4-4 is an example with
|
||||
similar annotations to those in Listing 4-3.
|
||||
Returning values can also transfer ownership. [Listing 4-4][Listing-4-4] is an example with
|
||||
similar annotations to those in [Listing 4-3][Listing-4-3].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-4-4]: #Listing-4-4
|
||||
<a name="Listing-4-4"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let s1 = gives_ownership(); // gives_ownership moves its return
|
||||
|
@ -525,10 +549,13 @@ It’s quite annoying that anything we pass in also needs to be passed back if w
|
|||
want to use it again, in addition to any data resulting from the body of the
|
||||
function that we might want to return as well.
|
||||
|
||||
It’s possible to return multiple values using a tuple, as shown in Listing 4-5.
|
||||
It’s possible to return multiple values using a tuple, as shown in [Listing 4-5][Listing-4-5].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-4-5]: #Listing-4-5
|
||||
<a name="Listing-4-5"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let s1 = String::from("hello");
|
||||
|
@ -550,3 +577,13 @@ fn calculate_length(s: String) -> (String, usize) {
|
|||
But this is too much ceremony and a lot of work for a concept that should be
|
||||
common. Luckily for us, Rust has a feature for this concept, called
|
||||
*references*.
|
||||
|
||||
[Listing-4-1]: ch04-01-what-is-ownership.html#Listing-4-1
|
||||
[Listing-4-2]: ch04-01-what-is-ownership.html#Listing-4-2
|
||||
[Figure-4-1]: ch04-01-what-is-ownership.html#Figure-4-1
|
||||
[Figure-4-2]: ch04-01-what-is-ownership.html#Figure-4-2
|
||||
[Figure-4-3]: ch04-01-what-is-ownership.html#Figure-4-3
|
||||
[Figure-4-4]: ch04-01-what-is-ownership.html#Figure-4-4
|
||||
[Listing-4-3]: ch04-01-what-is-ownership.html#Listing-4-3
|
||||
[Listing-4-4]: ch04-01-what-is-ownership.html#Listing-4-4
|
||||
[Listing-4-5]: ch04-01-what-is-ownership.html#Listing-4-5
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
## References and Borrowing
|
||||
|
||||
The issue with the tuple code in Listing 4-5 is that we have to return the
|
||||
The issue with the tuple code in [Listing 4-5][Listing-4-5] is that we have to return the
|
||||
`String` to the calling function so we can still use the `String` after the
|
||||
call to `calculate_length`, because the `String` was moved into
|
||||
`calculate_length`.
|
||||
|
@ -31,7 +31,10 @@ function return value is gone. Second, note that we pass `&s1` into
|
|||
`String`.
|
||||
|
||||
These ampersands are *references*, and they allow you to refer to some value
|
||||
without taking ownership of it. Figure 4-5 shows a diagram.
|
||||
without taking ownership of it. [Figure 4-5][Figure-4-5] shows a diagram.
|
||||
|
||||
[Figure-4-5]: #Figure-4-5
|
||||
<a name="Figure-4-5"></a>
|
||||
|
||||
<img alt="&String s pointing at String s1" src="img/trpl04-05.svg" class="center" />
|
||||
|
||||
|
@ -79,10 +82,13 @@ if a person owns something, you can borrow it from them. When you’re done, you
|
|||
have to give it back.
|
||||
|
||||
So what happens if we try to modify something we’re borrowing? Try the code in
|
||||
Listing 4-6. Spoiler alert: it doesn’t work!
|
||||
[Listing 4-6][Listing-4-6]. Spoiler alert: it doesn’t work!
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-4-6]: #Listing-4-6
|
||||
<a name="Listing-4-6"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let s = String::from("hello");
|
||||
|
@ -114,7 +120,7 @@ allowed to modify something we have a reference to.
|
|||
|
||||
### Mutable References
|
||||
|
||||
We can fix the error in the code from Listing 4-6 with just a small tweak:
|
||||
We can fix the error in the code from [Listing 4-6][Listing-4-6] with just a small tweak:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
|
@ -319,3 +325,7 @@ Let’s recap what we’ve discussed about references:
|
|||
* References must always be valid.
|
||||
|
||||
Next, we’ll look at a different kind of reference: slices.
|
||||
|
||||
[Listing-4-5]: ch04-01-what-is-ownership.html#Listing-4-5
|
||||
[Figure-4-5]: ch04-02-references-and-borrowing.html#Figure-4-5
|
||||
[Listing-4-6]: ch04-02-references-and-borrowing.html#Listing-4-6
|
||||
|
|
|
@ -18,10 +18,13 @@ fn first_word(s: &String) -> ?
|
|||
This function, `first_word`, has a `&String` as a parameter. We don’t want
|
||||
ownership, so this is fine. But what should we return? We don’t really have a
|
||||
way to talk about *part* of a string. However, we could return the index of the
|
||||
end of the word. Let’s try that, as shown in Listing 4-7.
|
||||
end of the word. Let’s try that, as shown in [Listing 4-7][Listing-4-7].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-4-7]: #Listing-4-7
|
||||
<a name="Listing-4-7"></a>
|
||||
|
||||
```rust
|
||||
fn first_word(s: &String) -> usize {
|
||||
let bytes = s.as_bytes();
|
||||
|
@ -83,11 +86,14 @@ We now have a way to find out the index of the end of the first word in the
|
|||
string, but there’s a problem. We’re returning a `usize` on its own, but it’s
|
||||
only a meaningful number in the context of the `&String`. In other words,
|
||||
because it’s a separate value from the `String`, there’s no guarantee that it
|
||||
will still be valid in the future. Consider the program in Listing 4-8 that
|
||||
uses the `first_word` function from Listing 4-7.
|
||||
will still be valid in the future. Consider the program in [Listing 4-8][Listing-4-8] that
|
||||
uses the `first_word` function from [Listing 4-7][Listing-4-7].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-4-8]: #Listing-4-8
|
||||
<a name="Listing-4-8"></a>
|
||||
|
||||
```rust
|
||||
# fn first_word(s: &String) -> usize {
|
||||
# let bytes = s.as_bytes();
|
||||
|
@ -161,7 +167,10 @@ the length of the slice, which corresponds to `ending_index` minus
|
|||
`starting_index`. So in the case of `let world = &s[6..11];`, `world` would be
|
||||
a slice that contains a pointer to the 7th byte of `s` with a length value of 5.
|
||||
|
||||
Figure 4-6 shows this in a diagram.
|
||||
[Figure 4-6][Figure-4-6] shows this in a diagram.
|
||||
|
||||
[Figure-4-6]: #Figure-4-6
|
||||
<a name="Figure-4-6"></a>
|
||||
|
||||
<img alt="world containing a pointer to the 6th byte of String s and a length 5" src="img/trpl04-06.svg" class="center" style="width: 50%;" />
|
||||
|
||||
|
@ -228,8 +237,8 @@ fn first_word(s: &String) -> &str {
|
|||
}
|
||||
```
|
||||
|
||||
We get the index for the end of the word in the same way as we did in Listing
|
||||
4-7, by looking for the first occurrence of a space. When we find a space, we
|
||||
We get the index for the end of the word in the same way as we did in [Listing 4-7][Listing-4-7],
|
||||
by looking for the first occurrence of a space. When we find a space, we
|
||||
return a string slice using the start of the string and the index of the space
|
||||
as the starting and ending indices.
|
||||
|
||||
|
@ -245,7 +254,7 @@ fn second_word(s: &String) -> &str {
|
|||
|
||||
We now have a straightforward API that’s much harder to mess up, because the
|
||||
compiler will ensure the references into the `String` remain valid. Remember
|
||||
the bug in the program in Listing 4-8, when we got the index to the end of the
|
||||
the bug in the program in [Listing 4-8][Listing-4-8], when we got the index to the end of the
|
||||
first word but then cleared the string so our index was invalid? That code was
|
||||
logically incorrect but didn’t show any immediate errors. The problems would
|
||||
show up later if we kept trying to use the first word index with an emptied
|
||||
|
@ -308,10 +317,13 @@ one more improvement on `first_word`, and that’s its signature:
|
|||
fn first_word(s: &String) -> &str {
|
||||
```
|
||||
|
||||
A more experienced Rustacean would write the signature shown in Listing 4-9
|
||||
A more experienced Rustacean would write the signature shown in [Listing 4-9][Listing-4-9]
|
||||
instead because it allows us to use the same function on both `String` values
|
||||
and `&str` values.
|
||||
|
||||
[Listing-4-9]: #Listing-4-9
|
||||
<a name="Listing-4-9"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn first_word(s: &str) -> &str {
|
||||
```
|
||||
|
@ -389,3 +401,8 @@ means you don’t have to write and debug extra code to get this control.
|
|||
Ownership affects how lots of other parts of Rust work, so we’ll talk about
|
||||
these concepts further throughout the rest of the book. Let’s move on to
|
||||
Chapter 5 and look at grouping pieces of data together in a `struct`.
|
||||
|
||||
[Listing-4-7]: ch04-03-slices.html#Listing-4-7
|
||||
[Listing-4-8]: ch04-03-slices.html#Listing-4-8
|
||||
[Figure-4-6]: ch04-03-slices.html#Figure-4-6
|
||||
[Listing-4-9]: ch04-03-slices.html#Listing-4-9
|
||||
|
|
|
@ -9,9 +9,12 @@ order of the data to specify or access the values of an instance.
|
|||
To define a struct, we enter the keyword `struct` and name the entire struct. A
|
||||
struct’s name should describe the significance of the pieces of data being
|
||||
grouped together. Then, inside curly brackets, we define the names and types of
|
||||
the pieces of data, which we call *fields*. For example, Listing 5-1 shows a
|
||||
the pieces of data, which we call *fields*. For example, [Listing 5-1][Listing-5-1] shows a
|
||||
struct that stores information about a user account.
|
||||
|
||||
[Listing-5-1]: #Listing-5-1
|
||||
<a name="Listing-5-1"></a>
|
||||
|
||||
```rust
|
||||
struct User {
|
||||
username: String,
|
||||
|
@ -31,7 +34,10 @@ data we want to store in those fields. We don’t have to specify the fields in
|
|||
the same order in which we declared them in the struct. In other words, the
|
||||
struct definition is like a general template for the type, and instances fill
|
||||
in that template with particular data to create values of the type. For
|
||||
example, we can declare a particular user as shown in Listing 5-2.
|
||||
example, we can declare a particular user as shown in [Listing 5-2][Listing-5-2].
|
||||
|
||||
[Listing-5-2]: #Listing-5-2
|
||||
<a name="Listing-5-2"></a>
|
||||
|
||||
```rust
|
||||
# struct User {
|
||||
|
@ -55,9 +61,12 @@ struct</span>
|
|||
To get a specific value from a struct, we can use dot notation. If we wanted
|
||||
just this user’s email address, we could use `user1.email` wherever we wanted
|
||||
to use this value. If the instance is mutable, we can change a value by using
|
||||
the dot notation and assigning into a particular field. Listing 5-3 shows how
|
||||
the dot notation and assigning into a particular field. [Listing 5-3][Listing-5-3] shows how
|
||||
to change the value in the `email` field of a mutable `User` instance.
|
||||
|
||||
[Listing-5-3]: #Listing-5-3
|
||||
<a name="Listing-5-3"></a>
|
||||
|
||||
```rust
|
||||
# struct User {
|
||||
# username: String,
|
||||
|
@ -84,10 +93,13 @@ only certain fields as mutable. As with any expression, we can construct a new
|
|||
instance of the struct as the last expression in the function body to
|
||||
implicitly return that new instance.
|
||||
|
||||
Listing 5-4 shows a `build_user` function that returns a `User` instance with
|
||||
[Listing 5-4][Listing-5-4] shows a `build_user` function that returns a `User` instance with
|
||||
the given email and username. The `active` field gets the value of `true`, and
|
||||
the `sign_in_count` gets a value of `1`.
|
||||
|
||||
[Listing-5-4]: #Listing-5-4
|
||||
<a name="Listing-5-4"></a>
|
||||
|
||||
```rust
|
||||
# struct User {
|
||||
# username: String,
|
||||
|
@ -117,9 +129,12 @@ would get even more annoying. Luckily, there’s a convenient shorthand!
|
|||
### Using the Field Init Shorthand when Variables and Fields Have the Same Name
|
||||
|
||||
Because the parameter names and the struct field names are exactly the same in
|
||||
Listing 5-4, we can use the *field init shorthand* syntax to rewrite
|
||||
[Listing 5-4][Listing-5-4], we can use the *field init shorthand* syntax to rewrite
|
||||
`build_user` so that it behaves exactly the same but doesn’t have the
|
||||
repetition of `email` and `username`, as shown in Listing 5-5.
|
||||
repetition of `email` and `username`, as shown in [Listing 5-5][Listing-5-5].
|
||||
|
||||
[Listing-5-5]: #Listing-5-5
|
||||
<a name="Listing-5-5"></a>
|
||||
|
||||
```rust
|
||||
# struct User {
|
||||
|
@ -154,9 +169,12 @@ than `email: email`.
|
|||
It’s often useful to create a new instance of a struct that uses most of an old
|
||||
instance’s values but changes some. You’ll do this using *struct update syntax*.
|
||||
|
||||
First, Listing 5-6 shows how we create a new `User` instance in `user2` without
|
||||
First, [Listing 5-6][Listing-5-6] shows how we create a new `User` instance in `user2` without
|
||||
the update syntax. We set new values for `email` and `username` but otherwise
|
||||
use the same values from `user1` that we created in Listing 5-2.
|
||||
use the same values from `user1` that we created in [Listing 5-2][Listing-5-2].
|
||||
|
||||
[Listing-5-6]: #Listing-5-6
|
||||
<a name="Listing-5-6"></a>
|
||||
|
||||
```rust
|
||||
# struct User {
|
||||
|
@ -185,9 +203,12 @@ let user2 = User {
|
|||
the values from `user1`</span>
|
||||
|
||||
Using struct update syntax, we can achieve the same effect with less code, as
|
||||
shown in Listing 5-7. The syntax `..` specifies that the remaining fields not
|
||||
shown in [Listing 5-7][Listing-5-7]. The syntax `..` specifies that the remaining fields not
|
||||
explicitly set should have the same value as the fields in the given instance.
|
||||
|
||||
[Listing-5-7]: #Listing-5-7
|
||||
<a name="Listing-5-7"></a>
|
||||
|
||||
```rust
|
||||
# struct User {
|
||||
# username: String,
|
||||
|
@ -214,7 +235,7 @@ let user2 = User {
|
|||
`email` and `username` values for a `User` instance but use the rest of the
|
||||
values from the fields of the instance in the `user1` variable</span>
|
||||
|
||||
The code in Listing 5-7 also creates an instance in `user2` that has a
|
||||
The code in [Listing 5-7][Listing-5-7] also creates an instance in `user2` that has a
|
||||
different value for `email` and `username` but has the same values for the
|
||||
`active` and `sign_in_count` fields from `user1`.
|
||||
|
||||
|
@ -258,7 +279,7 @@ itself. We’ll discuss traits in Chapter 10.
|
|||
|
||||
> ### Ownership of Struct Data
|
||||
>
|
||||
> In the `User` struct definition in Listing 5-1, we used the owned `String`
|
||||
> In the `User` struct definition in [Listing 5-1][Listing-5-1], we used the owned `String`
|
||||
> type rather than the `&str` string slice type. This is a deliberate choice
|
||||
> because we want instances of this struct to own all of its data and for that
|
||||
> data to be valid for as long as the entire struct is valid.
|
||||
|
@ -308,3 +329,11 @@ itself. We’ll discuss traits in Chapter 10.
|
|||
> In Chapter 10, we’ll discuss how to fix these errors so you can store
|
||||
> references in structs, but for now, we’ll fix errors like these using owned
|
||||
> types like `String` instead of references like `&str`.
|
||||
|
||||
[Listing-5-1]: ch05-01-defining-structs.html#Listing-5-1
|
||||
[Listing-5-2]: ch05-01-defining-structs.html#Listing-5-2
|
||||
[Listing-5-3]: ch05-01-defining-structs.html#Listing-5-3
|
||||
[Listing-5-4]: ch05-01-defining-structs.html#Listing-5-4
|
||||
[Listing-5-5]: ch05-01-defining-structs.html#Listing-5-5
|
||||
[Listing-5-6]: ch05-01-defining-structs.html#Listing-5-6
|
||||
[Listing-5-7]: ch05-01-defining-structs.html#Listing-5-7
|
||||
|
|
|
@ -6,11 +6,14 @@ refactor the program until we’re using structs instead.
|
|||
|
||||
Let’s make a new binary project with Cargo called *rectangles* that will take
|
||||
the width and height of a rectangle specified in pixels and calculate the area
|
||||
of the rectangle. Listing 5-8 shows a short program with one way of doing
|
||||
of the rectangle. [Listing 5-8][Listing-5-8] shows a short program with one way of doing
|
||||
exactly that in our project’s *src/main.rs*.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-5-8]: #Listing-5-8
|
||||
<a name="Listing-5-8"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let width1 = 30;
|
||||
|
@ -36,7 +39,7 @@ Now, run this program using `cargo run`:
|
|||
The area of the rectangle is 1500 square pixels.
|
||||
```
|
||||
|
||||
Even though Listing 5-8 works and figures out the area of the rectangle by
|
||||
Even though [Listing 5-8][Listing-5-8] works and figures out the area of the rectangle by
|
||||
calling the `area` function with each dimension, we can do better. The width
|
||||
and the height are related to each other because together they describe one
|
||||
rectangle.
|
||||
|
@ -55,10 +58,13 @@ we might do that in “The Tuple Type” section of Chapter 3: by using tuples.
|
|||
|
||||
### Refactoring with Tuples
|
||||
|
||||
Listing 5-9 shows another version of our program that uses tuples.
|
||||
[Listing 5-9][Listing-5-9] shows another version of our program that uses tuples.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-5-9]: #Listing-5-9
|
||||
<a name="Listing-5-9"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let rect1 = (30, 50);
|
||||
|
@ -94,10 +100,13 @@ our code.
|
|||
|
||||
We use structs to add meaning by labeling the data. We can transform the tuple
|
||||
we’re using into a data type with a name for the whole as well as names for the
|
||||
parts, as shown in Listing 5-10.
|
||||
parts, as shown in [Listing 5-10][Listing-5-10].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-5-10]: #Listing-5-10
|
||||
<a name="Listing-5-10"></a>
|
||||
|
||||
```rust
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
|
@ -142,12 +151,15 @@ and `1`. This is a win for clarity.
|
|||
### Adding Useful Functionality with Derived Traits
|
||||
|
||||
It’d be nice to be able to print an instance of `Rectangle` while we’re
|
||||
debugging our program and see the values for all its fields. Listing 5-11 tries
|
||||
debugging our program and see the values for all its fields. [Listing 5-11][Listing-5-11] tries
|
||||
using the `println!` macro as we have used in previous chapters. This won’t
|
||||
work, however.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-5-11]: #Listing-5-11
|
||||
<a name="Listing-5-11"></a>
|
||||
|
||||
```rust,ignore
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
|
@ -210,10 +222,13 @@ crate, add `#[derive(Debug)]` or manually implement it
|
|||
Rust *does* include functionality to print out debugging information, but we
|
||||
have to explicitly opt in to make that functionality available for our struct.
|
||||
To do that, we add the annotation `#[derive(Debug)]` just before the struct
|
||||
definition, as shown in Listing 5-12.
|
||||
definition, as shown in [Listing 5-12][Listing-5-12].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-5-12]: #Listing-5-12
|
||||
<a name="Listing-5-12"></a>
|
||||
|
||||
```rust
|
||||
#[derive(Debug)]
|
||||
struct Rectangle {
|
||||
|
@ -261,3 +276,9 @@ It would be helpful to tie this behavior more closely to our `Rectangle`
|
|||
struct, because it won’t work with any other type. Let’s look at how we can
|
||||
continue to refactor this code by turning the `area` function into an `area`
|
||||
*method* defined on our `Rectangle` type.
|
||||
|
||||
[Listing-5-8]: ch05-02-example-structs.html#Listing-5-8
|
||||
[Listing-5-9]: ch05-02-example-structs.html#Listing-5-9
|
||||
[Listing-5-10]: ch05-02-example-structs.html#Listing-5-10
|
||||
[Listing-5-11]: ch05-02-example-structs.html#Listing-5-11
|
||||
[Listing-5-12]: ch05-02-example-structs.html#Listing-5-12
|
||||
|
|
|
@ -12,10 +12,13 @@ instance of the struct the method is being called on.
|
|||
|
||||
Let’s change the `area` function that has a `Rectangle` instance as a parameter
|
||||
and instead make an `area` method defined on the `Rectangle` struct, as shown
|
||||
in Listing 5-13.
|
||||
in [Listing 5-13][Listing-5-13].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-5-13]: #Listing-5-13
|
||||
<a name="Listing-5-13"></a>
|
||||
|
||||
```rust
|
||||
#[derive(Debug)]
|
||||
struct Rectangle {
|
||||
|
@ -124,11 +127,14 @@ Let’s practice using methods by implementing a second method on the `Rectangle
|
|||
struct. This time, we want an instance of `Rectangle` to take another instance
|
||||
of `Rectangle` and return `true` if the second `Rectangle` can fit completely
|
||||
within `self`; otherwise it should return `false`. That is, we want to be able
|
||||
to write the program shown in Listing 5-14, once we’ve defined the `can_hold`
|
||||
to write the program shown in [Listing 5-14][Listing-5-14], once we’ve defined the `can_hold`
|
||||
method.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-5-14]: #Listing-5-14
|
||||
<a name="Listing-5-14"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let rect1 = Rectangle { width: 30, height: 50 };
|
||||
|
@ -164,10 +170,13 @@ calling the `can_hold` method. The return value of `can_hold` will be a
|
|||
Boolean, and the implementation will check whether the width and height of
|
||||
`self` are both greater than the width and height of the other `Rectangle`,
|
||||
respectively. Let’s add the new `can_hold` method to the `impl` block from
|
||||
Listing 5-13, shown in Listing 5-15.
|
||||
[Listing 5-13][Listing-5-13], shown in [Listing 5-15][Listing-5-15].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-5-15]: #Listing-5-15
|
||||
<a name="Listing-5-15"></a>
|
||||
|
||||
```rust
|
||||
# #[derive(Debug)]
|
||||
# struct Rectangle {
|
||||
|
@ -189,7 +198,7 @@ impl Rectangle {
|
|||
<span class="caption">Listing 5-15: Implementing the `can_hold` method on
|
||||
`Rectangle` that takes another `Rectangle` instance as a parameter</span>
|
||||
|
||||
When we run this code with the `main` function in Listing 5-14, we’ll get our
|
||||
When we run this code with the `main` function in [Listing 5-14][Listing-5-14], we’ll get our
|
||||
desired output. Methods can take multiple parameters that we add to the
|
||||
signature after the `self` parameter, and those parameters work just like
|
||||
parameters in functions.
|
||||
|
@ -232,10 +241,13 @@ namespaces created by modules. We’ll discuss modules in Chapter 7.
|
|||
|
||||
### Multiple `impl` Blocks
|
||||
|
||||
Each struct is allowed to have multiple `impl` blocks. For example, Listing
|
||||
5-15 is equivalent to the code shown in Listing 5-16, which has each method
|
||||
Each struct is allowed to have multiple `impl` blocks. For example, [Listing 5-15][Listing-5-15]
|
||||
is equivalent to the code shown in [Listing 5-16][Listing-5-16], which has each method
|
||||
in its own `impl` block.
|
||||
|
||||
[Listing-5-16]: #Listing-5-16
|
||||
<a name="Listing-5-16"></a>
|
||||
|
||||
```rust
|
||||
# #[derive(Debug)]
|
||||
# struct Rectangle {
|
||||
|
@ -256,7 +268,7 @@ impl Rectangle {
|
|||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 5-16: Rewriting Listing 5-15 using multiple `impl`
|
||||
<span class="caption">Listing 5-16: Rewriting [Listing 5-15][Listing-5-15] using multiple `impl`
|
||||
blocks</span>
|
||||
|
||||
There’s no reason to separate these methods into multiple `impl` blocks here,
|
||||
|
@ -274,3 +286,8 @@ instance available.
|
|||
|
||||
But structs aren’t the only way you can create custom types: let’s turn to
|
||||
Rust’s enum feature to add another tool to your toolbox.
|
||||
|
||||
[Listing-5-13]: ch05-03-method-syntax.html#Listing-5-13
|
||||
[Listing-5-14]: ch05-03-method-syntax.html#Listing-5-14
|
||||
[Listing-5-15]: ch05-03-method-syntax.html#Listing-5-15
|
||||
[Listing-5-16]: ch05-03-method-syntax.html#Listing-5-16
|
||||
|
|
|
@ -73,7 +73,10 @@ route(IpAddrKind::V6);
|
|||
Using enums has even more advantages. Thinking more about our IP address type,
|
||||
at the moment we don’t have a way to store the actual IP address *data*; we
|
||||
only know what *kind* it is. Given that you just learned about structs in
|
||||
Chapter 5, you might tackle this problem as shown in Listing 6-1.
|
||||
Chapter 5, you might tackle this problem as shown in [Listing 6-1][Listing-6-1].
|
||||
|
||||
[Listing-6-1]: #Listing-6-1
|
||||
<a name="Listing-6-1"></a>
|
||||
|
||||
```rust
|
||||
enum IpAddrKind {
|
||||
|
@ -182,9 +185,12 @@ we can still create and use our own definition without conflict because we
|
|||
haven’t brought the standard library’s definition into our scope. We’ll talk
|
||||
more about bringing types into scope in Chapter 7.
|
||||
|
||||
Let’s look at another example of an enum in Listing 6-2: this one has a wide
|
||||
Let’s look at another example of an enum in [Listing 6-2][Listing-6-2]: this one has a wide
|
||||
variety of types embedded in its variants.
|
||||
|
||||
[Listing-6-2]: #Listing-6-2
|
||||
<a name="Listing-6-2"></a>
|
||||
|
||||
```rust
|
||||
enum Message {
|
||||
Quit,
|
||||
|
@ -204,7 +210,7 @@ This enum has four variants with different types:
|
|||
* `Write` includes a single `String`.
|
||||
* `ChangeColor` includes three `i32` values.
|
||||
|
||||
Defining an enum with variants such as the ones in Listing 6-2 is similar to
|
||||
Defining an enum with variants such as the ones in [Listing 6-2][Listing-6-2] is similar to
|
||||
defining different kinds of struct definitions, except the enum doesn’t use the
|
||||
`struct` keyword and all the variants are grouped together under the `Message`
|
||||
type. The following structs could hold the same data that the preceding enum
|
||||
|
@ -222,7 +228,7 @@ struct ChangeColorMessage(i32, i32, i32); // tuple struct
|
|||
|
||||
But if we used the different structs, which each have their own type, we
|
||||
couldn’t as easily define a function to take any of these kinds of messages as
|
||||
we could with the `Message` enum defined in Listing 6-2, which is a single type.
|
||||
we could with the `Message` enum defined in [Listing 6-2][Listing-6-2], which is a single type.
|
||||
|
||||
There is one more similarity between enums and structs: just as we’re able to
|
||||
define methods on structs using `impl`, we’re also able to define methods on
|
||||
|
@ -397,3 +403,6 @@ value available. The `match` expression is a control flow construct that does
|
|||
just this when used with enums: it will run different code depending on which
|
||||
variant of the enum it has, and that code can use the data inside the matching
|
||||
value.
|
||||
|
||||
[Listing-6-1]: ch06-01-defining-an-enum.html#Listing-6-1
|
||||
[Listing-6-2]: ch06-01-defining-an-enum.html#Listing-6-2
|
||||
|
|
|
@ -17,7 +17,10 @@ the value falls into the associated code block to be used during execution.
|
|||
Because we just mentioned coins, let’s use them as an example using `match`! We
|
||||
can write a function that can take an unknown United States coin and, in a
|
||||
similar way as the counting machine, determine which coin it is and return its
|
||||
value in cents, as shown here in Listing 6-3.
|
||||
value in cents, as shown here in [Listing 6-3][Listing-6-3].
|
||||
|
||||
[Listing-6-3]: #Listing-6-3
|
||||
<a name="Listing-6-3"></a>
|
||||
|
||||
```rust
|
||||
enum Coin {
|
||||
|
@ -56,14 +59,14 @@ When the `match` expression executes, it compares the resulting value against
|
|||
the pattern of each arm, in order. If a pattern matches the value, the code
|
||||
associated with that pattern is executed. If that pattern doesn’t match the
|
||||
value, execution continues to the next arm, much as in a coin-sorting machine.
|
||||
We can have as many arms as we need: in Listing 6-3, our `match` has four arms.
|
||||
We can have as many arms as we need: in [Listing 6-3][Listing-6-3], our `match` has four arms.
|
||||
|
||||
The code associated with each arm is an expression, and the resulting value of
|
||||
the expression in the matching arm is the value that gets returned for the
|
||||
entire `match` expression.
|
||||
|
||||
Curly brackets typically aren’t used if the match arm code is short, as it is
|
||||
in Listing 6-3 where each arm just returns a value. If you want to run multiple
|
||||
in [Listing 6-3][Listing-6-3] where each arm just returns a value. If you want to run multiple
|
||||
lines of code in a match arm, you can use curly brackets. For example, the
|
||||
following code would print “Lucky penny!” every time the method was called with
|
||||
a `Coin::Penny` but would still return the last value of the block, `1`:
|
||||
|
@ -100,7 +103,10 @@ From 1999 through 2008, the United States minted quarters with different
|
|||
designs for each of the 50 states on one side. No other coins got state
|
||||
designs, so only quarters have this extra value. We can add this information to
|
||||
our `enum` by changing the `Quarter` variant to include a `UsState` value stored
|
||||
inside it, which we’ve done here in Listing 6-4.
|
||||
inside it, which we’ve done here in [Listing 6-4][Listing-6-4].
|
||||
|
||||
[Listing-6-4]: #Listing-6-4
|
||||
<a name="Listing-6-4"></a>
|
||||
|
||||
```rust
|
||||
#[derive(Debug)] // so we can inspect the state in a minute
|
||||
|
@ -179,7 +185,10 @@ the function should return the `None` value and not attempt to perform any
|
|||
operations.
|
||||
|
||||
This function is very easy to write, thanks to `match`, and will look like
|
||||
Listing 6-5.
|
||||
[Listing 6-5][Listing-6-5].
|
||||
|
||||
[Listing-6-5]: #Listing-6-5
|
||||
<a name="Listing-6-5"></a>
|
||||
|
||||
```rust
|
||||
fn plus_one(x: Option<i32>) -> Option<i32> {
|
||||
|
@ -217,7 +226,7 @@ Does `Some(5)` match `Some(i)`? Why yes it does! We have the same variant. The
|
|||
code in the match arm is then executed, so we add 1 to the value of `i` and
|
||||
create a new `Some` value with our total `6` inside.
|
||||
|
||||
Now let’s consider the second call of `plus_one` in Listing 6-5, where `x` is
|
||||
Now let’s consider the second call of `plus_one` in [Listing 6-5][Listing-6-5], where `x` is
|
||||
`None`. We enter the `match` and compare to the first arm.
|
||||
|
||||
```rust,ignore
|
||||
|
@ -293,3 +302,7 @@ list before the `_` placeholder.
|
|||
|
||||
However, the `match` expression can be a bit wordy in a situation in which we
|
||||
care about only *one* of the cases. For this situation, Rust provides `if let`.
|
||||
|
||||
[Listing-6-3]: ch06-02-match.html#Listing-6-3
|
||||
[Listing-6-4]: ch06-02-match.html#Listing-6-4
|
||||
[Listing-6-5]: ch06-02-match.html#Listing-6-5
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
|
||||
The `if let` syntax lets you combine `if` and `let` into a less verbose way to
|
||||
handle values that match one pattern while ignoring the rest. Consider the
|
||||
program in Listing 6-6 that matches on an `Option<u8>` value but only wants to
|
||||
program in [Listing 6-6][Listing-6-6] that matches on an `Option<u8>` value but only wants to
|
||||
execute code if the value is 3.
|
||||
|
||||
[Listing-6-6]: #Listing-6-6
|
||||
<a name="Listing-6-6"></a>
|
||||
|
||||
```rust
|
||||
let some_u8_value = Some(0u8);
|
||||
match some_u8_value {
|
||||
|
@ -22,7 +25,7 @@ have to add `_ => ()` after processing just one variant, which is a lot of
|
|||
boilerplate code to add.
|
||||
|
||||
Instead, we could write this in a shorter way using `if let`. The following
|
||||
code behaves the same as the `match` in Listing 6-6:
|
||||
code behaves the same as the `match` in [Listing 6-6][Listing-6-6]:
|
||||
|
||||
```rust
|
||||
# let some_u8_value = Some(0u8);
|
||||
|
@ -47,7 +50,7 @@ runs code when the value matches one pattern and then ignores all other values.
|
|||
We can include an `else` with an `if let`. The block of code that goes with the
|
||||
`else` is the same as the block of code that would go with the `_` case in the
|
||||
`match` expression that is equivalent to the `if let` and `else`. Recall the
|
||||
`Coin` enum definition in Listing 6-4, where the `Quarter` variant also held a
|
||||
`Coin` enum definition in [Listing 6-4][Listing-6-4], where the `Quarter` variant also held a
|
||||
`UsState` value. If we wanted to count all non-quarter coins we see while also
|
||||
announcing the state of the quarters, we could do that with a `match`
|
||||
expression like this:
|
||||
|
@ -116,3 +119,6 @@ function expects.
|
|||
In order to provide a well-organized API to your users that is straightforward
|
||||
to use and only exposes exactly what your users will need, let’s now turn to
|
||||
Rust’s modules.
|
||||
|
||||
[Listing-6-6]: ch06-03-if-let.html#Listing-6-6
|
||||
[Listing-6-4]: ch06-02-match.html#Listing-6-4
|
||||
|
|
|
@ -70,10 +70,13 @@ would need to specify the module and use the namespace syntax `::` like so:
|
|||
|
||||
We can also have multiple modules, side by side, in the same *src/lib.rs* file.
|
||||
For example, to also have a `client` module that has a function named
|
||||
`connect`, we can add it as shown in Listing 7-1.
|
||||
`connect`, we can add it as shown in [Listing 7-1][Listing-7-1].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-7-1]: #Listing-7-1
|
||||
<a name="Listing-7-1"></a>
|
||||
|
||||
```rust
|
||||
mod network {
|
||||
fn connect() {
|
||||
|
@ -103,10 +106,13 @@ related functionality organized together and separate functionality apart. The
|
|||
way you choose to organize your code depends on how you think about the
|
||||
relationship between the parts of your code. For instance, the `client` code
|
||||
and its `connect` function might make more sense to users of our library if
|
||||
they were inside the `network` namespace instead, as in Listing 7-2.
|
||||
they were inside the `network` namespace instead, as in [Listing 7-2][Listing-7-2].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-7-2]: #Listing-7-2
|
||||
<a name="Listing-7-2"></a>
|
||||
|
||||
```rust
|
||||
mod network {
|
||||
fn connect() {
|
||||
|
@ -123,14 +129,14 @@ mod network {
|
|||
`network` module</span>
|
||||
|
||||
In your *src/lib.rs* file, replace the existing `mod network` and `mod client`
|
||||
definitions with the ones in Listing 7-2, which have the `client` module as an
|
||||
definitions with the ones in [Listing 7-2][Listing-7-2], which have the `client` module as an
|
||||
inner module of `network`. The functions `network::connect` and
|
||||
`network::client::connect` are both named `connect`, but they don’t conflict
|
||||
with each other because they’re in different namespaces.
|
||||
|
||||
In this way, modules form a hierarchy. The contents of *src/lib.rs* are at the
|
||||
topmost level, and the submodules are at lower levels. Here’s what the
|
||||
organization of our example in Listing 7-1 looks like when thought of as a
|
||||
organization of our example in [Listing 7-1][Listing-7-1] looks like when thought of as a
|
||||
hierarchy:
|
||||
|
||||
```text
|
||||
|
@ -139,7 +145,7 @@ communicator
|
|||
└── client
|
||||
```
|
||||
|
||||
And here’s the hierarchy corresponding to the example in Listing 7-2:
|
||||
And here’s the hierarchy corresponding to the example in [Listing 7-2][Listing-7-2]:
|
||||
|
||||
```text
|
||||
communicator
|
||||
|
@ -147,7 +153,7 @@ communicator
|
|||
└── client
|
||||
```
|
||||
|
||||
The hierarchy shows that in Listing 7-2, `client` is a child of the `network`
|
||||
The hierarchy shows that in [Listing 7-2][Listing-7-2], `client` is a child of the `network`
|
||||
module rather than a sibling. More complicated projects can have many modules,
|
||||
and they’ll need to be organized logically in order for you to keep track of
|
||||
them. What “logically” means in your project is up to you and depends on how
|
||||
|
@ -161,10 +167,13 @@ Modules form a hierarchical structure, much like another structure in computing
|
|||
that you’re used to: filesystems! We can use Rust’s module system along with
|
||||
multiple files to split up Rust projects so not everything lives in
|
||||
*src/lib.rs* or *src/main.rs*. For this example, let’s start with the code in
|
||||
Listing 7-3.
|
||||
[Listing 7-3][Listing-7-3].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-7-3]: #Listing-7-3
|
||||
<a name="Listing-7-3"></a>
|
||||
|
||||
```rust
|
||||
mod client {
|
||||
fn connect() {
|
||||
|
@ -202,10 +211,13 @@ These would be good reasons to separate the `client`, `network`, and `server`
|
|||
modules from *src/lib.rs* and place them into their own files.
|
||||
|
||||
First, let’s replace the `client` module code with only the declaration of the
|
||||
`client` module so that *src/lib.rs* looks like code shown in Listing 7-4.
|
||||
`client` module so that *src/lib.rs* looks like code shown in [Listing 7-4][Listing-7-4].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-7-4]: #Listing-7-4
|
||||
<a name="Listing-7-4"></a>
|
||||
|
||||
```rust,ignore
|
||||
mod client;
|
||||
|
||||
|
@ -345,7 +357,10 @@ fn connect() {
|
|||
}
|
||||
```
|
||||
|
||||
When we try to run `cargo build`, we’ll get the error shown in Listing 7-5.
|
||||
When we try to run `cargo build`, we’ll get the error shown in [Listing 7-5][Listing-7-5].
|
||||
|
||||
[Listing-7-5]: #Listing-7-5
|
||||
<a name="Listing-7-5"></a>
|
||||
|
||||
```text
|
||||
$ cargo build
|
||||
|
@ -375,7 +390,7 @@ The error says we `cannot declare a new module at this location` and is
|
|||
pointing to the `mod server;` line in *src/network.rs*. So *src/network.rs* is
|
||||
different than *src/lib.rs* somehow: keep reading to understand why.
|
||||
|
||||
The note in the middle of Listing 7-5 is actually very helpful because it
|
||||
The note in the middle of [Listing 7-5][Listing-7-5] is actually very helpful because it
|
||||
points out something we haven’t yet talked about doing:
|
||||
|
||||
```text
|
||||
|
@ -401,7 +416,7 @@ $ mv src/server.rs src/network
|
|||
|
||||
Now when we try to run `cargo build`, compilation will work (we’ll still have
|
||||
warnings, though). Our module layout still looks exactly the same as it did when
|
||||
we had all the code in *src/lib.rs* in Listing 7-3:
|
||||
we had all the code in *src/lib.rs* in [Listing 7-3][Listing-7-3]:
|
||||
|
||||
```text
|
||||
communicator
|
||||
|
@ -479,3 +494,9 @@ The modules should be declared in their parent module’s file using the `mod`
|
|||
keyword.
|
||||
|
||||
Next, we’ll talk about the `pub` keyword and get rid of those warnings!
|
||||
|
||||
[Listing-7-1]: ch07-01-mod-and-the-filesystem.html#Listing-7-1
|
||||
[Listing-7-2]: ch07-01-mod-and-the-filesystem.html#Listing-7-2
|
||||
[Listing-7-3]: ch07-01-mod-and-the-filesystem.html#Listing-7-3
|
||||
[Listing-7-4]: ch07-01-mod-and-the-filesystem.html#Listing-7-4
|
||||
[Listing-7-5]: ch07-01-mod-and-the-filesystem.html#Listing-7-5
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
## Controlling Visibility with `pub`
|
||||
|
||||
We resolved the error messages shown in Listing 7-5 by moving the `network` and
|
||||
We resolved the error messages shown in [Listing 7-5][Listing-7-5] by moving the `network` and
|
||||
`network::server` code into the *src/network/mod.rs* and
|
||||
*src/network/server.rs* files, respectively. At that point, `cargo build` was
|
||||
able to build our project, but we still get warning messages saying that the
|
||||
|
@ -216,11 +216,14 @@ Overall, these are the rules for item visibility:
|
|||
### Privacy Examples
|
||||
|
||||
Let’s look at a few more privacy examples to get some practice. Create a new
|
||||
library project and enter the code in Listing 7-6 into your new project’s
|
||||
library project and enter the code in [Listing 7-6][Listing-7-6] into your new project’s
|
||||
*src/lib.rs*.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-7-6]: #Listing-7-6
|
||||
<a name="Listing-7-6"></a>
|
||||
|
||||
```rust,ignore
|
||||
mod outermost {
|
||||
pub fn middle_function() {}
|
||||
|
@ -285,3 +288,6 @@ them out!
|
|||
that we want to refer to the modules starting from the root module.)
|
||||
|
||||
Next, let’s talk about bringing items into scope with the `use` keyword.
|
||||
|
||||
[Listing-7-5]: ch07-01-mod-and-the-filesystem.html#Listing-7-5
|
||||
[Listing-7-6]: ch07-02-controlling-visibility-with-pub.html#Listing-7-6
|
||||
|
|
|
@ -2,10 +2,13 @@
|
|||
|
||||
We’ve covered how to call functions defined within a module using the module
|
||||
name as part of the call, as in the call to the `nested_modules` function shown
|
||||
here in Listing 7-7.
|
||||
here in [Listing 7-7][Listing-7-7].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-7-7]: #Listing-7-7
|
||||
<a name="Listing-7-7"></a>
|
||||
|
||||
```rust
|
||||
pub mod a {
|
||||
pub mod series {
|
||||
|
@ -270,3 +273,5 @@ present a tidy public API to your library users.
|
|||
|
||||
Next, we’ll look at some collection data structures in the standard library
|
||||
that you can use in your nice, neat code.
|
||||
|
||||
[Listing-7-7]: ch07-03-importing-names-with-use.html#Listing-7-7
|
||||
|
|
|
@ -9,7 +9,10 @@ lines of text in a file or the prices of items in a shopping cart.
|
|||
### Creating a New Vector
|
||||
|
||||
To create a new, empty vector, we can call the `Vec::new` function, as shown in
|
||||
Listing 8-1.
|
||||
[Listing 8-1][Listing-8-1].
|
||||
|
||||
[Listing-8-1]: #Listing-8-1
|
||||
<a name="Listing-8-1"></a>
|
||||
|
||||
```rust
|
||||
let v: Vec<i32> = Vec::new();
|
||||
|
@ -24,16 +27,19 @@ store. This is an important point. Vectors are implemented using generics;
|
|||
we’ll cover how to use generics with your own types in Chapter 10. For now,
|
||||
know that the `Vec<T>` type provided by the standard library can hold any type,
|
||||
and when a specific vector holds a specific type, the type is specified within
|
||||
angle brackets. In Listing 8-1, we’ve told Rust that the `Vec<T>` in `v` will
|
||||
angle brackets. In [Listing 8-1][Listing-8-1], we’ve told Rust that the `Vec<T>` in `v` will
|
||||
hold elements of the `i32` type.
|
||||
|
||||
In more realistic code, Rust can often infer the type of value you want to
|
||||
store once you insert values, so you rarely need to do this type annotation.
|
||||
It’s more common to create a `Vec<T>` that has initial values, and Rust
|
||||
provides the `vec!` macro for convenience. The macro will create a new vector
|
||||
that holds the values you give it. Listing 8-2 creates a new `Vec<i32>` that
|
||||
that holds the values you give it. [Listing 8-2][Listing-8-2] creates a new `Vec<i32>` that
|
||||
holds the values `1`, `2`, and `3`.
|
||||
|
||||
[Listing-8-2]: #Listing-8-2
|
||||
<a name="Listing-8-2"></a>
|
||||
|
||||
```rust
|
||||
let v = vec![1, 2, 3];
|
||||
```
|
||||
|
@ -48,7 +54,10 @@ to modify a vector.
|
|||
### Updating a Vector
|
||||
|
||||
To create a vector and then add elements to it, we can use the `push` method,
|
||||
as shown in Listing 8-3.
|
||||
as shown in [Listing 8-3][Listing-8-3].
|
||||
|
||||
[Listing-8-3]: #Listing-8-3
|
||||
<a name="Listing-8-3"></a>
|
||||
|
||||
```rust
|
||||
let mut v = Vec::new();
|
||||
|
@ -70,7 +79,10 @@ we don’t need the `Vec<i32>` annotation.
|
|||
### Dropping a Vector Drops Its Elements
|
||||
|
||||
Like any other `struct`, a vector is freed when it goes out of scope, as
|
||||
annotated in Listing 8-4.
|
||||
annotated in [Listing 8-4][Listing-8-4].
|
||||
|
||||
[Listing-8-4]: #Listing-8-4
|
||||
<a name="Listing-8-4"></a>
|
||||
|
||||
```rust
|
||||
{
|
||||
|
@ -96,9 +108,12 @@ read their contents is a good next step. There are two ways to reference a
|
|||
value stored in a vector. In the examples, we’ve annotated the types of the
|
||||
values that are returned from these functions for extra clarity.
|
||||
|
||||
Listing 8-5 shows both methods of accessing a value in a vector, either with
|
||||
[Listing 8-5][Listing-8-5] shows both methods of accessing a value in a vector, either with
|
||||
indexing syntax or the `get` method.
|
||||
|
||||
[Listing-8-5]: #Listing-8-5
|
||||
<a name="Listing-8-5"></a>
|
||||
|
||||
```rust
|
||||
let v = vec![1, 2, 3, 4, 5];
|
||||
|
||||
|
@ -119,7 +134,10 @@ Rust has two ways to reference an element so you can choose how the program
|
|||
behaves when you try to use an index value that the vector doesn’t have an
|
||||
element for. As an example, let’s see what a program will do if it has a vector
|
||||
that holds five elements and then tries to access an element at index 100, as
|
||||
shown in Listing 8-6.
|
||||
shown in [Listing 8-6][Listing-8-6].
|
||||
|
||||
[Listing-8-6]: #Listing-8-6
|
||||
<a name="Listing-8-6"></a>
|
||||
|
||||
```rust,should_panic
|
||||
let v = vec![1, 2, 3, 4, 5];
|
||||
|
@ -150,10 +168,13 @@ When the program has a valid reference, the borrow checker enforces the
|
|||
ownership and borrowing rules (covered in Chapter 4) to ensure this reference
|
||||
and any other references to the contents of the vector remain valid. Recall the
|
||||
rule that states you can’t have mutable and immutable references in the same
|
||||
scope. That rule applies in Listing 8-7, where we hold an immutable reference to
|
||||
scope. That rule applies in [Listing 8-7][Listing-8-7], where we hold an immutable reference to
|
||||
the first element in a vector and try to add an element to the end, which won’t
|
||||
work.
|
||||
|
||||
[Listing-8-7]: #Listing-8-7
|
||||
<a name="Listing-8-7"></a>
|
||||
|
||||
```rust,ignore
|
||||
let mut v = vec![1, 2, 3, 4, 5];
|
||||
|
||||
|
@ -181,7 +202,7 @@ error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immuta
|
|||
| - immutable borrow ends here
|
||||
```
|
||||
|
||||
The code in Listing 8-7 might look like it should work: why should a reference
|
||||
The code in [Listing 8-7][Listing-8-7] might look like it should work: why should a reference
|
||||
to the first element care about what changes at the end of the vector? This
|
||||
error is due to the way vectors work: adding a new element onto the end of the
|
||||
vector might require allocating new memory and copying the old elements to the
|
||||
|
@ -196,10 +217,13 @@ programs from ending up in that situation.
|
|||
### Iterating over the Values in a Vector
|
||||
|
||||
If we want to access each element in a vector in turn, we can iterate through
|
||||
all of the elements rather than use indexes to access one at a time. Listing
|
||||
8-8 shows how to use a `for` loop to get immutable references to each element
|
||||
all of the elements rather than use indexes to access one at a time. [Listing 8-8][Listing-8-8]
|
||||
shows how to use a `for` loop to get immutable references to each element
|
||||
in a vector of `i32` values and print them.
|
||||
|
||||
[Listing-8-8]: #Listing-8-8
|
||||
<a name="Listing-8-8"></a>
|
||||
|
||||
```rust
|
||||
let v = vec![100, 32, 57];
|
||||
for i in &v {
|
||||
|
@ -211,9 +235,12 @@ for i in &v {
|
|||
iterating over the elements using a `for` loop</span>
|
||||
|
||||
We can also iterate over mutable references to each element in a mutable vector
|
||||
in order to make changes to all the elements. The `for` loop in Listing 8-9
|
||||
in order to make changes to all the elements. The `for` loop in [Listing 8-9][Listing-8-9]
|
||||
will add `50` to each element.
|
||||
|
||||
[Listing-8-9]: #Listing-8-9
|
||||
<a name="Listing-8-9"></a>
|
||||
|
||||
```rust
|
||||
let mut v = vec![100, 32, 57];
|
||||
for i in &mut v {
|
||||
|
@ -241,7 +268,10 @@ some of the columns in the row contain integers, some floating-point numbers,
|
|||
and some strings. We can define an enum whose variants will hold the different
|
||||
value types, and then all the enum variants will be considered the same type:
|
||||
that of the enum. Then we can create a vector that holds that enum and so,
|
||||
ultimately, holds different types. We’ve demonstrated this in Listing 8-10.
|
||||
ultimately, holds different types. We’ve demonstrated this in [Listing 8-10][Listing-8-10].
|
||||
|
||||
[Listing-8-10]: #Listing-8-10
|
||||
<a name="Listing-8-10"></a>
|
||||
|
||||
```rust
|
||||
enum SpreadsheetCell {
|
||||
|
@ -278,3 +308,14 @@ to review the API documentation for all the many useful methods defined on
|
|||
`Vec<T>` by the standard library. For example, in addition to `push`, a `pop`
|
||||
method removes and returns the last element. Let’s move on to the next
|
||||
collection type: `String`!
|
||||
|
||||
[Listing-8-1]: ch08-01-vectors.html#Listing-8-1
|
||||
[Listing-8-2]: ch08-01-vectors.html#Listing-8-2
|
||||
[Listing-8-3]: ch08-01-vectors.html#Listing-8-3
|
||||
[Listing-8-4]: ch08-01-vectors.html#Listing-8-4
|
||||
[Listing-8-5]: ch08-01-vectors.html#Listing-8-5
|
||||
[Listing-8-6]: ch08-01-vectors.html#Listing-8-6
|
||||
[Listing-8-7]: ch08-01-vectors.html#Listing-8-7
|
||||
[Listing-8-8]: ch08-01-vectors.html#Listing-8-8
|
||||
[Listing-8-9]: ch08-01-vectors.html#Listing-8-9
|
||||
[Listing-8-10]: ch08-01-vectors.html#Listing-8-10
|
||||
|
|
|
@ -44,8 +44,10 @@ API documentation for more about how to use them and when each is appropriate.
|
|||
### Creating a New String
|
||||
|
||||
Many of the same operations available with `Vec<T>` are available with `String`
|
||||
as well, starting with the `new` function to create a string, shown in Listing
|
||||
8-11.
|
||||
as well, starting with the `new` function to create a string, shown in [Listing 8-11][Listing-8-11].
|
||||
|
||||
[Listing-8-11]: #Listing-8-11
|
||||
<a name="Listing-8-11"></a>
|
||||
|
||||
```rust
|
||||
let mut s = String::new();
|
||||
|
@ -56,9 +58,12 @@ let mut s = String::new();
|
|||
This line creates a new empty string called `s`, which we can then load data
|
||||
into. Often, we’ll have some initial data that we want to start the string
|
||||
with. For that, we use the `to_string` method, which is available on any type
|
||||
that implements the `Display` trait, as string literals do. Listing 8-12 shows
|
||||
that implements the `Display` trait, as string literals do. [Listing 8-12][Listing-8-12] shows
|
||||
two examples.
|
||||
|
||||
[Listing-8-12]: #Listing-8-12
|
||||
<a name="Listing-8-12"></a>
|
||||
|
||||
```rust
|
||||
let data = "initial contents";
|
||||
|
||||
|
@ -74,9 +79,12 @@ let s = "initial contents".to_string();
|
|||
This code creates a string containing `initial contents`.
|
||||
|
||||
We can also use the function `String::from` to create a `String` from a string
|
||||
literal. The code in Listing 8-13 is equivalent to the code from Listing 8-12
|
||||
literal. The code in [Listing 8-13][Listing-8-13] is equivalent to the code from [Listing 8-12][Listing-8-12]
|
||||
that uses `to_string`.
|
||||
|
||||
[Listing-8-13]: #Listing-8-13
|
||||
<a name="Listing-8-13"></a>
|
||||
|
||||
```rust
|
||||
let s = String::from("initial contents");
|
||||
```
|
||||
|
@ -90,7 +98,10 @@ redundant, but they all have their place! In this case, `String::from` and
|
|||
`to_string` do the same thing, so which you choose is a matter of style.
|
||||
|
||||
Remember that strings are UTF-8 encoded, so we can include any properly encoded
|
||||
data in them, as shown in Listing 8-14.
|
||||
data in them, as shown in [Listing 8-14][Listing-8-14].
|
||||
|
||||
[Listing-8-14]: #Listing-8-14
|
||||
<a name="Listing-8-14"></a>
|
||||
|
||||
```rust
|
||||
let hello = String::from("السلام عليكم");
|
||||
|
@ -120,7 +131,10 @@ use the `+` operator or the `format!` macro to concatenate `String` values.
|
|||
#### Appending to a String with `push_str` and `push`
|
||||
|
||||
We can grow a `String` by using the `push_str` method to append a string slice,
|
||||
as shown in Listing 8-15.
|
||||
as shown in [Listing 8-15][Listing-8-15].
|
||||
|
||||
[Listing-8-15]: #Listing-8-15
|
||||
<a name="Listing-8-15"></a>
|
||||
|
||||
```rust
|
||||
let mut s = String::from("foo");
|
||||
|
@ -132,9 +146,12 @@ using the `push_str` method</span>
|
|||
|
||||
After these two lines, `s` will contain `foobar`. The `push_str` method takes a
|
||||
string slice because we don’t necessarily want to take ownership of the
|
||||
parameter. For example, the code in Listing 8-16 shows that it would be
|
||||
parameter. For example, the code in [Listing 8-16][Listing-8-16] shows that it would be
|
||||
unfortunate if we weren’t able to use `s2` after appending its contents to `s1`.
|
||||
|
||||
[Listing-8-16]: #Listing-8-16
|
||||
<a name="Listing-8-16"></a>
|
||||
|
||||
```rust
|
||||
let mut s1 = String::from("foo");
|
||||
let s2 = "bar";
|
||||
|
@ -149,9 +166,12 @@ If the `push_str` method took ownership of `s2`, we wouldn’t be able to print
|
|||
its value on the last line. However, this code works as we’d expect!
|
||||
|
||||
The `push` method takes a single character as a parameter and adds it to the
|
||||
`String`. Listing 8-17 shows code that adds the letter *l* to a `String` using
|
||||
`String`. [Listing 8-17][Listing-8-17] shows code that adds the letter *l* to a `String` using
|
||||
the `push` method.
|
||||
|
||||
[Listing-8-17]: #Listing-8-17
|
||||
<a name="Listing-8-17"></a>
|
||||
|
||||
```rust
|
||||
let mut s = String::from("lo");
|
||||
s.push('l');
|
||||
|
@ -165,7 +185,10 @@ As a result of this code, `s` will contain `lol`.
|
|||
#### Concatenation with the `+` Operator or the `format!` Macro
|
||||
|
||||
Often, you’ll want to combine two existing strings. One way is to use the `+`
|
||||
operator, as shown in Listing 8-18.
|
||||
operator, as shown in [Listing 8-18][Listing-8-18].
|
||||
|
||||
[Listing-8-18]: #Listing-8-18
|
||||
<a name="Listing-8-18"></a>
|
||||
|
||||
```rust
|
||||
let s1 = String::from("Hello, ");
|
||||
|
@ -197,7 +220,7 @@ First, `s2` has an `&`, meaning that we’re adding a *reference* of the second
|
|||
string to the first string because of the `s` parameter in the `add` function:
|
||||
we can only add a `&str` to a `String`; we can’t add two `String` values
|
||||
together. But wait—the type of `&s2` is `&String`, not `&str`, as specified in
|
||||
the second parameter to `add`. So why does Listing 8-18 compile?
|
||||
the second parameter to `add`. So why does [Listing 8-18][Listing-8-18] compile?
|
||||
|
||||
The reason we’re able to use `&s2` in the call to `add` is that the compiler
|
||||
can *coerce* the `&String` argument into a `&str`. When we call the `add`
|
||||
|
@ -207,7 +230,7 @@ not take ownership of the `s` parameter, `s2` will still be a valid `String`
|
|||
after this operation.
|
||||
|
||||
Second, we can see in the signature that `add` takes ownership of `self`,
|
||||
because `self` does *not* have an `&`. This means `s1` in Listing 8-18 will be
|
||||
because `self` does *not* have an `&`. This means `s1` in [Listing 8-18][Listing-8-18] will be
|
||||
moved into the `add` call and no longer be valid after that. So although `let
|
||||
s3 = s1 + &s2;` looks like it will copy both strings and create a new one, this
|
||||
statement actually takes ownership of `s1`, appends a copy of the contents of
|
||||
|
@ -248,7 +271,10 @@ easier to read and doesn’t take ownership of any of its parameters.
|
|||
In many other programming languages, accessing individual characters in a
|
||||
string by referencing them by index is a valid and common operation. However,
|
||||
if you try to access parts of a `String` using indexing syntax in Rust, you’ll
|
||||
get an error. Consider the invalid code in Listing 8-19.
|
||||
get an error. Consider the invalid code in [Listing 8-19][Listing-8-19].
|
||||
|
||||
[Listing-8-19]: #Listing-8-19
|
||||
<a name="Listing-8-19"></a>
|
||||
|
||||
```rust,ignore
|
||||
let s1 = String::from("hello");
|
||||
|
@ -277,7 +303,7 @@ memory.
|
|||
#### Internal Representation
|
||||
|
||||
A `String` is a wrapper over a `Vec<u8>`. Let’s look at some of our properly
|
||||
encoded UTF-8 example strings from Listing 8-14. First, this one:
|
||||
encoded UTF-8 example strings from [Listing 8-14][Listing-8-14]. First, this one:
|
||||
|
||||
```rust
|
||||
let len = String::from("Hola").len();
|
||||
|
@ -450,3 +476,13 @@ from having to handle errors involving non-ASCII characters later in your
|
|||
development life cycle.
|
||||
|
||||
Let’s switch to something a bit less complex: hash maps!
|
||||
|
||||
[Listing-8-11]: ch08-02-strings.html#Listing-8-11
|
||||
[Listing-8-12]: ch08-02-strings.html#Listing-8-12
|
||||
[Listing-8-13]: ch08-02-strings.html#Listing-8-13
|
||||
[Listing-8-14]: ch08-02-strings.html#Listing-8-14
|
||||
[Listing-8-15]: ch08-02-strings.html#Listing-8-15
|
||||
[Listing-8-16]: ch08-02-strings.html#Listing-8-16
|
||||
[Listing-8-17]: ch08-02-strings.html#Listing-8-17
|
||||
[Listing-8-18]: ch08-02-strings.html#Listing-8-18
|
||||
[Listing-8-19]: ch08-02-strings.html#Listing-8-19
|
||||
|
|
|
@ -20,10 +20,13 @@ As always, check the standard library documentation for more information.
|
|||
### Creating a New Hash Map
|
||||
|
||||
You can create an empty hash map with `new` and add elements with `insert`. In
|
||||
Listing 8-20, we’re keeping track of the scores of two teams whose names are
|
||||
[Listing 8-20][Listing-8-20], we’re keeping track of the scores of two teams whose names are
|
||||
Blue and Yellow. The Blue team starts with 10 points, and the Yellow team
|
||||
starts with 50.
|
||||
|
||||
[Listing-8-20]: #Listing-8-20
|
||||
<a name="Listing-8-20"></a>
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
@ -53,7 +56,10 @@ vector of tuples, where each tuple consists of a key and its value. The
|
|||
`HashMap`. For example, if we had the team names and initial scores in two
|
||||
separate vectors, we could use the `zip` method to create a vector of tuples
|
||||
where “Blue” is paired with 10, and so forth. Then we could use the `collect`
|
||||
method to turn that vector of tuples into a hash map, as shown in Listing 8-21.
|
||||
method to turn that vector of tuples into a hash map, as shown in [Listing 8-21][Listing-8-21].
|
||||
|
||||
[Listing-8-21]: #Listing-8-21
|
||||
<a name="Listing-8-21"></a>
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
|
@ -77,7 +83,10 @@ contains based on the types of the data in the vectors.
|
|||
|
||||
For types that implement the `Copy` trait, like `i32`, the values are copied
|
||||
into the hash map. For owned values like `String`, the values will be moved and
|
||||
the hash map will be the owner of those values, as demonstrated in Listing 8-22.
|
||||
the hash map will be the owner of those values, as demonstrated in [Listing 8-22][Listing-8-22].
|
||||
|
||||
[Listing-8-22]: #Listing-8-22
|
||||
<a name="Listing-8-22"></a>
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
|
@ -105,7 +114,10 @@ the “Validating References with Lifetimes” section in Chapter 10.
|
|||
### Accessing Values in a Hash Map
|
||||
|
||||
We can get a value out of the hash map by providing its key to the `get`
|
||||
method, as shown in Listing 8-23.
|
||||
method, as shown in [Listing 8-23][Listing-8-23].
|
||||
|
||||
[Listing-8-23]: #Listing-8-23
|
||||
<a name="Listing-8-23"></a>
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
|
@ -166,10 +178,13 @@ of these!
|
|||
|
||||
If we insert a key and a value into a hash map and then insert that same key
|
||||
with a different value, the value associated with that key will be replaced.
|
||||
Even though the code in Listing 8-24 calls `insert` twice, the hash map will
|
||||
Even though the code in [Listing 8-24][Listing-8-24] calls `insert` twice, the hash map will
|
||||
only contain one key/value pair because we’re inserting the value for the Blue
|
||||
team’s key both times.
|
||||
|
||||
[Listing-8-24]: #Listing-8-24
|
||||
<a name="Listing-8-24"></a>
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
@ -196,7 +211,10 @@ that takes the key you want to check as a parameter. The return value of the
|
|||
might not exist. Let’s say we want to check whether the key for the Yellow team
|
||||
has a value associated with it. If it doesn’t, we want to insert the value 50,
|
||||
and the same for the Blue team. Using the `entry` API, the code looks like
|
||||
Listing 8-25.
|
||||
[Listing 8-25][Listing-8-25].
|
||||
|
||||
[Listing-8-25]: #Listing-8-25
|
||||
<a name="Listing-8-25"></a>
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
|
@ -219,7 +237,7 @@ inserts the parameter as the new value for this key and returns a mutable
|
|||
reference to the new value. This technique is much cleaner than writing the
|
||||
logic ourselves and, in addition, plays more nicely with the borrow checker.
|
||||
|
||||
Running the code in Listing 8-25 will print `{"Yellow": 50, "Blue": 10}`. The
|
||||
Running the code in [Listing 8-25][Listing-8-25] will print `{"Yellow": 50, "Blue": 10}`. The
|
||||
first call to `entry` will insert the key for the Yellow team with the value
|
||||
50 because the Yellow team doesn’t have a value already. The second call to
|
||||
`entry` will not change the hash map because the Blue team already has the
|
||||
|
@ -228,12 +246,15 @@ value 10.
|
|||
#### Updating a Value Based on the Old Value
|
||||
|
||||
Another common use case for hash maps is to look up a key’s value and then
|
||||
update it based on the old value. For instance, Listing 8-26 shows code that
|
||||
update it based on the old value. For instance, [Listing 8-26][Listing-8-26] shows code that
|
||||
counts how many times each word appears in some text. We use a hash map with
|
||||
the words as keys and increment the value to keep track of how many times we’ve
|
||||
seen that word. If it’s the first time we’ve seen a word, we’ll first insert
|
||||
the value 0.
|
||||
|
||||
[Listing-8-26]: #Listing-8-26
|
||||
<a name="Listing-8-26"></a>
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
@ -297,3 +318,11 @@ and hash maps have that will be helpful for these exercises!
|
|||
|
||||
We’re getting into more complex programs in which operations can fail, so, it’s
|
||||
a perfect time to discuss error handling. We’ll do that next!
|
||||
|
||||
[Listing-8-20]: ch08-03-hash-maps.html#Listing-8-20
|
||||
[Listing-8-21]: ch08-03-hash-maps.html#Listing-8-21
|
||||
[Listing-8-22]: ch08-03-hash-maps.html#Listing-8-22
|
||||
[Listing-8-23]: ch08-03-hash-maps.html#Listing-8-23
|
||||
[Listing-8-24]: ch08-03-hash-maps.html#Listing-8-24
|
||||
[Listing-8-25]: ch08-03-hash-maps.html#Listing-8-25
|
||||
[Listing-8-26]: ch08-03-hash-maps.html#Listing-8-26
|
||||
|
|
|
@ -63,11 +63,14 @@ backtrace is in more detail next.
|
|||
|
||||
Let’s look at another example to see what it’s like when a `panic!` call comes
|
||||
from a library because of a bug in our code instead of from our code calling
|
||||
the macro directly. Listing 9-1 has some code that attempts to access an
|
||||
the macro directly. [Listing 9-1][Listing-9-1] has some code that attempts to access an
|
||||
element by index in a vector.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-9-1]: #Listing-9-1
|
||||
<a name="Listing-9-1"></a>
|
||||
|
||||
```rust,should_panic
|
||||
fn main() {
|
||||
let v = vec![1, 2, 3];
|
||||
|
@ -122,7 +125,10 @@ mentioning your files are code that your code called; the lines below are code
|
|||
that called your code. These lines might include core Rust code, standard
|
||||
library code, or crates that you’re using. Let’s try getting a backtrace by
|
||||
setting the `RUST_BACKTRACE` environment variable to any value except 0.
|
||||
Listing 9-2 shows output similar to what you’ll see.
|
||||
[Listing 9-2][Listing-9-2] shows output similar to what you’ll see.
|
||||
|
||||
[Listing-9-2]: #Listing-9-2
|
||||
<a name="Listing-9-2"></a>
|
||||
|
||||
```text
|
||||
$ RUST_BACKTRACE=1 cargo run
|
||||
|
@ -175,10 +181,10 @@ information, debug symbols must be enabled. Debug symbols are enabled by
|
|||
default when using `cargo build` or `cargo run` without the `--release` flag,
|
||||
as we have here.
|
||||
|
||||
In the output in Listing 9-2, line 11 of the backtrace points to the line in
|
||||
In the output in [Listing 9-2][Listing-9-2], line 11 of the backtrace points to the line in
|
||||
our project that’s causing the problem: line 4 of *src/main.rs*. If we don’t
|
||||
want our program to panic, the location pointed to by the first line mentioning
|
||||
a file we wrote is where we should start investigating. In Listing 9-1, where
|
||||
a file we wrote is where we should start investigating. In [Listing 9-1][Listing-9-1], where
|
||||
we deliberately wrote code that would panic in order to demonstrate how to use
|
||||
backtraces, the way to fix the panic is to not request an element at index 99
|
||||
from a vector that only contains 3 items. When your code panics in the future,
|
||||
|
@ -189,3 +195,6 @@ We’ll come back to `panic!` and when we should and should not use `panic!` to
|
|||
handle error conditions in the “To `panic!` or Not to `panic!`” section later
|
||||
in this chapter. Next, we’ll look at how to recover from an error using
|
||||
`Result`.
|
||||
|
||||
[Listing-9-1]: ch09-01-unrecoverable-errors-with-panic.html#Listing-9-1
|
||||
[Listing-9-2]: ch09-01-unrecoverable-errors-with-panic.html#Listing-9-2
|
||||
|
|
|
@ -29,10 +29,13 @@ library has defined on it in many different situations where the successful
|
|||
value and error value we want to return may differ.
|
||||
|
||||
Let’s call a function that returns a `Result` value because the function could
|
||||
fail. In Listing 9-3 we try to open a file.
|
||||
fail. In [Listing 9-3][Listing-9-3] we try to open a file.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-9-3]: #Listing-9-3
|
||||
<a name="Listing-9-3"></a>
|
||||
|
||||
```rust
|
||||
use std::fs::File;
|
||||
|
||||
|
@ -87,13 +90,16 @@ an instance of `Ok` that contains a file handle. In the case where it fails,
|
|||
the value in `f` will be an instance of `Err` that contains more information
|
||||
about the kind of error that happened.
|
||||
|
||||
We need to add to the code in Listing 9-3 to take different actions depending
|
||||
on the value `File::open` returns. Listing 9-4 shows one way to handle the
|
||||
We need to add to the code in [Listing 9-3][Listing-9-3] to take different actions depending
|
||||
on the value `File::open` returns. [Listing 9-4][Listing-9-4] shows one way to handle the
|
||||
`Result` using a basic tool, the `match` expression that we discussed in
|
||||
Chapter 6.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-9-4]: #Listing-9-4
|
||||
<a name="Listing-9-4"></a>
|
||||
|
||||
```rust,should_panic
|
||||
use std::fs::File;
|
||||
|
||||
|
@ -135,19 +141,22 @@ As usual, this output tells us exactly what has gone wrong.
|
|||
|
||||
### Matching on Different Errors
|
||||
|
||||
The code in Listing 9-4 will `panic!` no matter why `File::open` failed. What
|
||||
The code in [Listing 9-4][Listing-9-4] will `panic!` no matter why `File::open` failed. What
|
||||
we want to do instead is take different actions for different failure reasons:
|
||||
if `File::open` failed because the file doesn’t exist, we want to create the
|
||||
file and return the handle to the new file. If `File::open` failed for any
|
||||
other reason—for example, because we didn’t have permission to open the file—we
|
||||
still want the code to `panic!` in the same way as it did in Listing 9-4. Look
|
||||
at Listing 9-5, which adds another arm to the `match`.
|
||||
still want the code to `panic!` in the same way as it did in [Listing 9-4][Listing-9-4]. Look
|
||||
at [Listing 9-5][Listing-9-5], which adds another arm to the `match`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
<!-- ignore this test because otherwise it creates hello.txt which causes other
|
||||
tests to fail lol -->
|
||||
|
||||
[Listing-9-5]: #Listing-9-5
|
||||
<a name="Listing-9-5"></a>
|
||||
|
||||
```rust,ignore
|
||||
use std::fs::File;
|
||||
use std::io::ErrorKind;
|
||||
|
@ -213,7 +222,7 @@ Using `match` works well enough, but it can be a bit verbose and doesn’t alway
|
|||
communicate intent well. The `Result<T, E>` type has many helper methods
|
||||
defined on it to do various tasks. One of those methods, called `unwrap`, is a
|
||||
shortcut method that is implemented just like the `match` expression we wrote
|
||||
in Listing 9-4. If the `Result` value is the `Ok` variant, `unwrap` will return
|
||||
in [Listing 9-4][Listing-9-4]. If the `Result` value is the `Ok` variant, `unwrap` will return
|
||||
the value inside the `Ok`. If the `Result` is the `Err` variant, `unwrap` will
|
||||
call the `panic!` macro for us. Here is an example of `unwrap` in action:
|
||||
|
||||
|
@ -276,12 +285,15 @@ error to the calling code so that it can decide what to do. This is known as
|
|||
might be more information or logic that dictates how the error should be
|
||||
handled than what you have available in the context of your code.
|
||||
|
||||
For example, Listing 9-6 shows a function that reads a username from a file. If
|
||||
For example, [Listing 9-6][Listing-9-6] shows a function that reads a username from a file. If
|
||||
the file doesn’t exist or can’t be read, this function will return those errors
|
||||
to the code that called this function.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-9-6]: #Listing-9-6
|
||||
<a name="Listing-9-6"></a>
|
||||
|
||||
```rust
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
|
@ -323,7 +335,7 @@ function and the `read_to_string` method.
|
|||
|
||||
The body of the function starts by calling the `File::open` function. Then we
|
||||
handle the `Result` value returned with a `match` similar to the `match` in
|
||||
Listing 9-4, only instead of calling `panic!` in the `Err` case, we return
|
||||
[Listing 9-4][Listing-9-4], only instead of calling `panic!` in the `Err` case, we return
|
||||
early from this function and pass the error value from `File::open` back to the
|
||||
calling code as this function’s error value. If `File::open` succeeds, we store
|
||||
the file handle in the variable `f` and continue.
|
||||
|
@ -353,12 +365,15 @@ question mark operator `?` to make this easier.
|
|||
|
||||
#### A Shortcut for Propagating Errors: the `?` Operator
|
||||
|
||||
Listing 9-7 shows an implementation of `read_username_from_file` that has the
|
||||
same functionality as it had in Listing 9-6, but this implementation uses the
|
||||
[Listing 9-7][Listing-9-7] shows an implementation of `read_username_from_file` that has the
|
||||
same functionality as it had in [Listing 9-6][Listing-9-6], but this implementation uses the
|
||||
`?` operator.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-9-7]: #Listing-9-7
|
||||
<a name="Listing-9-7"></a>
|
||||
|
||||
```rust
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
|
@ -376,14 +391,14 @@ fn read_username_from_file() -> Result<String, io::Error> {
|
|||
calling code using the `?` operator</span>
|
||||
|
||||
The `?` placed after a `Result` value is defined to work in almost the same way
|
||||
as the `match` expressions we defined to handle the `Result` values in Listing
|
||||
9-6. If the value of the `Result` is an `Ok`, the value inside the `Ok` will
|
||||
as the `match` expressions we defined to handle the `Result` values in [Listing 9-6][Listing-9-6].
|
||||
If the value of the `Result` is an `Ok`, the value inside the `Ok` will
|
||||
get returned from this expression, and the program will continue. If the value
|
||||
is an `Err`, the value inside the `Err` will be returned from the whole
|
||||
function as if we had used the `return` keyword so the error value gets
|
||||
propagated to the calling code.
|
||||
|
||||
There is a difference between what the `match` expression from Listing 9-6 and
|
||||
There is a difference between what the `match` expression from [Listing 9-6][Listing-9-6] and
|
||||
the `?` operator do: error values used with `?` go through the `from` function,
|
||||
defined in the `From` trait in the standard library, which is used to convert
|
||||
errors from one type into another. When the `?` operator calls the `from`
|
||||
|
@ -394,7 +409,7 @@ might fail for many different reasons. As long as each error type implements
|
|||
the `from` function to define how to convert itself to the returned error type,
|
||||
the `?` operator takes care of the conversion automatically.
|
||||
|
||||
In the context of Listing 9-7, the `?` at the end of the `File::open` call will
|
||||
In the context of [Listing 9-7][Listing-9-7], the `?` at the end of the `File::open` call will
|
||||
return the value inside an `Ok` to the variable `f`. If an error occurs, the
|
||||
`?` operator will return early out of the whole function and give any `Err`
|
||||
value to the calling code. The same thing applies to the `?` at the end of the
|
||||
|
@ -402,10 +417,13 @@ value to the calling code. The same thing applies to the `?` at the end of the
|
|||
|
||||
The `?` operator eliminates a lot of boilerplate and makes this function’s
|
||||
implementation simpler. We could even shorten this code further by chaining
|
||||
method calls immediately after the `?`, as shown in Listing 9-8.
|
||||
method calls immediately after the `?`, as shown in [Listing 9-8][Listing-9-8].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-9-8]: #Listing-9-8
|
||||
<a name="Listing-9-8"></a>
|
||||
|
||||
```rust
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
|
@ -429,14 +447,14 @@ chained the call to `read_to_string` directly onto the result of
|
|||
`File::open("hello.txt")?`. We still have a `?` at the end of the
|
||||
`read_to_string` call, and we still return an `Ok` value containing the
|
||||
username in `s` when both `File::open` and `read_to_string` succeed rather than
|
||||
returning errors. The functionality is again the same as in Listing 9-6 and
|
||||
Listing 9-7; this is just a different, more ergonomic way to write it.
|
||||
returning errors. The functionality is again the same as in [Listing 9-6][Listing-9-6] and
|
||||
[Listing 9-7][Listing-9-7]; this is just a different, more ergonomic way to write it.
|
||||
|
||||
#### The `?` Operator Can Only Be Used in Functions That Return `Result`
|
||||
|
||||
The `?` operator can only be used in functions that have a return type of
|
||||
`Result`, because it is defined to work in the same way as the `match`
|
||||
expression we defined in Listing 9-6. The part of the `match` that requires a
|
||||
expression we defined in [Listing 9-6][Listing-9-6]. The part of the `match` that requires a
|
||||
return type of `Result` is `return Err(e)`, so the return type of the function
|
||||
must be a `Result` to be compatible with this `return`.
|
||||
|
||||
|
@ -477,3 +495,10 @@ operator to potentially propagate the error to the calling code.
|
|||
Now that we’ve discussed the details of calling `panic!` or returning `Result`,
|
||||
let’s return to the topic of how to decide which is appropriate to use in which
|
||||
cases.
|
||||
|
||||
[Listing-9-3]: ch09-02-recoverable-errors-with-result.html#Listing-9-3
|
||||
[Listing-9-4]: ch09-02-recoverable-errors-with-result.html#Listing-9-4
|
||||
[Listing-9-5]: ch09-02-recoverable-errors-with-result.html#Listing-9-5
|
||||
[Listing-9-6]: ch09-02-recoverable-errors-with-result.html#Listing-9-6
|
||||
[Listing-9-7]: ch09-02-recoverable-errors-with-result.html#Listing-9-7
|
||||
[Listing-9-8]: ch09-02-recoverable-errors-with-result.html#Listing-9-8
|
||||
|
|
|
@ -168,10 +168,13 @@ tedious (and might impact performance).
|
|||
Instead, we can make a new type and put the validations in a function to create
|
||||
an instance of the type rather than repeating the validations everywhere. That
|
||||
way, it’s safe for functions to use the new type in their signatures and
|
||||
confidently use the values they receive. Listing 9-9 shows one way to define a
|
||||
confidently use the values they receive. [Listing 9-9][Listing-9-9] shows one way to define a
|
||||
`Guess` type that will only create an instance of `Guess` if the `new` function
|
||||
receives a value between 1 and 100.
|
||||
|
||||
[Listing-9-9]: #Listing-9-9
|
||||
<a name="Listing-9-9"></a>
|
||||
|
||||
```rust
|
||||
pub struct Guess {
|
||||
value: u32,
|
||||
|
@ -242,3 +245,5 @@ situations will make your code more reliable in the face of inevitable problems.
|
|||
Now that you’ve seen useful ways that the standard library uses generics with
|
||||
the `Option` and `Result` enums, we’ll talk about how generics work and how you
|
||||
can use them in your code.
|
||||
|
||||
[Listing-9-9]: ch09-03-to-panic-or-not-to-panic.html#Listing-9-9
|
||||
|
|
|
@ -36,10 +36,13 @@ you recognize duplicated code to extract into a function, you’ll start to
|
|||
recognize duplicated code that can use generics.
|
||||
|
||||
Consider a short program that finds the largest number in a list, as shown in
|
||||
Listing 10-1.
|
||||
[Listing 10-1][Listing-10-1].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-1]: #Listing-10-1
|
||||
<a name="Listing-10-1"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let number_list = vec![34, 50, 25, 100, 65];
|
||||
|
@ -70,11 +73,14 @@ After considering all the numbers in the list, `largest` should hold the
|
|||
largest number, which in this case is 100.
|
||||
|
||||
To find the largest number in two different lists of numbers, we can duplicate
|
||||
the code in Listing 10-1 and use the same logic at two different places in the
|
||||
program, as shown in Listing 10-2.
|
||||
the code in [Listing 10-1][Listing-10-1] and use the same logic at two different places in the
|
||||
program, as shown in [Listing 10-2][Listing-10-2].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-2]: #Listing-10-2
|
||||
<a name="Listing-10-2"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let number_list = vec![34, 50, 25, 100, 65];
|
||||
|
@ -114,13 +120,16 @@ function that operates on any list of integers given to it in a parameter. This
|
|||
solution makes our code clearer and lets us express the concept of finding the
|
||||
largest number in a list abstractly.
|
||||
|
||||
In Listing 10-3, we extracted the code that finds the largest number into a
|
||||
function named `largest`. Unlike the code in Listing 10-1, which can find the
|
||||
In [Listing 10-3][Listing-10-3], we extracted the code that finds the largest number into a
|
||||
function named `largest`. Unlike the code in [Listing 10-1][Listing-10-1], which can find the
|
||||
largest number in only one particular list, this program can find the largest
|
||||
number in two different lists.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-3]: #Listing-10-3
|
||||
<a name="Listing-10-3"></a>
|
||||
|
||||
```rust
|
||||
fn largest(list: &[i32]) -> i32 {
|
||||
let mut largest = list[0];
|
||||
|
@ -157,8 +166,8 @@ concrete slice of `i32` values that we might pass into the function. As a
|
|||
result, when we call the function, the code runs on the specific values that we
|
||||
pass in.
|
||||
|
||||
In sum, here are the steps we took to change the code from Listing 10-2 to
|
||||
Listing 10-3:
|
||||
In sum, here are the steps we took to change the code from [Listing 10-2][Listing-10-2] to
|
||||
[Listing 10-3][Listing-10-3]:
|
||||
|
||||
1. Identify duplicate code.
|
||||
2. Extract the duplicate code into the body of the function and specify the
|
||||
|
@ -173,3 +182,7 @@ abstract types.
|
|||
For example, say we had two functions: one that finds the largest item in a
|
||||
slice of `i32` values and one that finds the largest item in a slice of `char`
|
||||
values. How would we eliminate that duplication? Let’s find out!
|
||||
|
||||
[Listing-10-1]: ch10-00-generics.html#Listing-10-1
|
||||
[Listing-10-2]: ch10-00-generics.html#Listing-10-2
|
||||
[Listing-10-3]: ch10-00-generics.html#Listing-10-3
|
||||
|
|
|
@ -12,11 +12,14 @@ signature of the function where we would usually specify the data types of the
|
|||
parameters and return value. Doing so makes our code more flexible and provides
|
||||
more functionality to callers of our function while preventing code duplication.
|
||||
|
||||
Continuing with our `largest` function, Listing 10-4 shows two functions that
|
||||
Continuing with our `largest` function, [Listing 10-4][Listing-10-4] shows two functions that
|
||||
both find the largest value in a slice.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-4]: #Listing-10-4
|
||||
<a name="Listing-10-4"></a>
|
||||
|
||||
```rust
|
||||
fn largest_i32(list: &[i32]) -> i32 {
|
||||
let mut largest = list[0];
|
||||
|
@ -60,7 +63,7 @@ fn main() {
|
|||
<span class="caption">Listing 10-4: Two functions that differ only in their
|
||||
names and the types in their signatures</span>
|
||||
|
||||
The `largest_i32` function is the one we extracted in Listing 10-3 that finds
|
||||
The `largest_i32` function is the one we extracted in [Listing 10-3][Listing-10-3] that finds
|
||||
the largest `i32` in a slice. The `largest_char` function finds the largest
|
||||
`char` in a slice. The function bodies have the same code, so let’s eliminate
|
||||
the duplication by introducing a generic type parameter in a single function.
|
||||
|
@ -87,13 +90,16 @@ We read this definition as: the function `largest` is generic over some type
|
|||
`T`. This function has one parameter named `list`, which is a slice of values
|
||||
of type `T`. The `largest` function will return a value of the same type `T`.
|
||||
|
||||
Listing 10-5 shows the combined `largest` function definition using the generic
|
||||
[Listing 10-5][Listing-10-5] shows the combined `largest` function definition using the generic
|
||||
data type in its signature. The listing also shows how we can call the function
|
||||
with either a slice of `i32` values or `char` values. Note that this code won’t
|
||||
compile yet, but we’ll fix it later in this chapter.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-5]: #Listing-10-5
|
||||
<a name="Listing-10-5"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn largest<T>(list: &[T]) -> T {
|
||||
let mut largest = list[0];
|
||||
|
@ -148,11 +154,14 @@ ways of using generic type parameters.
|
|||
### In Struct Definitions
|
||||
|
||||
We can also define structs to use a generic type parameter in one or more
|
||||
fields using the `<>` syntax. Listing 10-6 shows how to define a `Point<T>`
|
||||
fields using the `<>` syntax. [Listing 10-6][Listing-10-6] shows how to define a `Point<T>`
|
||||
struct to hold `x` and `y` coordinate values of any type.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-6]: #Listing-10-6
|
||||
<a name="Listing-10-6"></a>
|
||||
|
||||
```rust
|
||||
struct Point<T> {
|
||||
x: T,
|
||||
|
@ -178,10 +187,13 @@ Note that because we’ve used only one generic type to define `Point<T>`, this
|
|||
definition says that the `Point<T>` struct is generic over some type `T`, and
|
||||
the fields `x` and `y` are *both* that same type, whatever that type may be. If
|
||||
we create an instance of a `Point<T>` that has values of different types, as in
|
||||
Listing 10-7, our code won’t compile.
|
||||
[Listing 10-7][Listing-10-7], our code won’t compile.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-7]: #Listing-10-7
|
||||
<a name="Listing-10-7"></a>
|
||||
|
||||
```rust,ignore
|
||||
struct Point<T> {
|
||||
x: T,
|
||||
|
@ -215,11 +227,14 @@ floating-point variable
|
|||
|
||||
To define a `Point` struct where `x` and `y` are both generics but could have
|
||||
different types, we can use multiple generic type parameters. For example, in
|
||||
Listing 10-8, we can change the definition of `Point` to be generic over types
|
||||
[Listing 10-8][Listing-10-8], we can change the definition of `Point` to be generic over types
|
||||
`T` and `U` where `x` is of type `T` and `y` is of type `U`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-8]: #Listing-10-8
|
||||
<a name="Listing-10-8"></a>
|
||||
|
||||
```rust
|
||||
struct Point<T, U> {
|
||||
x: T,
|
||||
|
@ -276,7 +291,7 @@ The `Result` enum is generic over two types, `T` and `E`, and has two variants:
|
|||
`E`. This definition makes it convenient to use the `Result` enum anywhere we
|
||||
have an operation that might succeed (return a value of some type `T`) or fail
|
||||
(return an error of some type `E`). In fact, this is what we used to open a
|
||||
file in Listing 9-3, where `T` was filled in with the type `std::fs::File` when
|
||||
file in [Listing 9-3][Listing-9-3], where `T` was filled in with the type `std::fs::File` when
|
||||
the file was opened successfully and `E` was filled in with the type
|
||||
`std::io::Error` when there were problems opening the file.
|
||||
|
||||
|
@ -287,11 +302,14 @@ avoid duplication by using generic types instead.
|
|||
### In Method Definitions
|
||||
|
||||
We can implement methods on structs and enums (as we did in Chapter 5) and use
|
||||
generic types in their definitions, too. Listing 10-9 shows the `Point<T>`
|
||||
struct we defined in Listing 10-6 with a method named `x` implemented on it.
|
||||
generic types in their definitions, too. [Listing 10-9][Listing-10-9] shows the `Point<T>`
|
||||
struct we defined in [Listing 10-6][Listing-10-6] with a method named `x` implemented on it.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-9]: #Listing-10-9
|
||||
<a name="Listing-10-9"></a>
|
||||
|
||||
```rust
|
||||
struct Point<T> {
|
||||
x: T,
|
||||
|
@ -324,9 +342,12 @@ generic type after `impl`, Rust can identify that the type in the angle
|
|||
brackets in `Point` is a generic type rather than a concrete type.
|
||||
|
||||
We could, for example, implement methods only on `Point<f32>` instances rather
|
||||
than on `Point<T>` instances with any generic type. In Listing 10-10 we use the
|
||||
than on `Point<T>` instances with any generic type. In [Listing 10-10][Listing-10-10] we use the
|
||||
concrete type `f32`, meaning we don’t declare any types after `impl`.
|
||||
|
||||
[Listing-10-10]: #Listing-10-10
|
||||
<a name="Listing-10-10"></a>
|
||||
|
||||
```rust
|
||||
# struct Point<T> {
|
||||
# x: T,
|
||||
|
@ -350,8 +371,8 @@ point is from the point at coordinates (0.0, 0.0) and uses mathematical
|
|||
operations that are available only for floating point types.
|
||||
|
||||
Generic type parameters in a struct definition aren’t always the same as those
|
||||
you use in that struct’s method signatures. For example, Listing 10-11 defines
|
||||
the method `mixup` on the `Point<T, U>` struct from Listing 10-8. The method
|
||||
you use in that struct’s method signatures. For example, [Listing 10-11][Listing-10-11] defines
|
||||
the method `mixup` on the `Point<T, U>` struct from [Listing 10-8][Listing-10-8]. The method
|
||||
takes another `Point` as a parameter, which might have different types than the
|
||||
`self` `Point` we’re calling `mixup` on. The method creates a new `Point`
|
||||
instance with the `x` value from the `self` `Point` (of type `T`) and the `y`
|
||||
|
@ -359,6 +380,9 @@ value from the passed-in `Point` (of type `W`).
|
|||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-11]: #Listing-10-11
|
||||
<a name="Listing-10-11"></a>
|
||||
|
||||
```rust
|
||||
struct Point<T, U> {
|
||||
x: T,
|
||||
|
@ -414,7 +438,7 @@ code into specific code by filling in the concrete types that are used when
|
|||
compiled.
|
||||
|
||||
In this process, the compiler does the opposite of the steps we used to create
|
||||
the generic function in Listing 10-5: the compiler looks at all the places
|
||||
the generic function in [Listing 10-5][Listing-10-5]: the compiler looks at all the places
|
||||
where generic code is called and generates code for the concrete types the
|
||||
generic code is called with.
|
||||
|
||||
|
@ -460,3 +484,14 @@ instance, we pay no runtime cost for using generics. When the code runs, it
|
|||
performs just as it would if we had duplicated each definition by hand. The
|
||||
process of monomorphization makes Rust’s generics extremely efficient at
|
||||
runtime.
|
||||
|
||||
[Listing-10-4]: ch10-01-syntax.html#Listing-10-4
|
||||
[Listing-10-5]: ch10-01-syntax.html#Listing-10-5
|
||||
[Listing-10-6]: ch10-01-syntax.html#Listing-10-6
|
||||
[Listing-10-7]: ch10-01-syntax.html#Listing-10-7
|
||||
[Listing-10-8]: ch10-01-syntax.html#Listing-10-8
|
||||
[Listing-10-9]: ch10-01-syntax.html#Listing-10-9
|
||||
[Listing-10-10]: ch10-01-syntax.html#Listing-10-10
|
||||
[Listing-10-11]: ch10-01-syntax.html#Listing-10-11
|
||||
[Listing-9-3]: ch09-02-recoverable-errors-with-result.html#Listing-9-3
|
||||
[Listing-10-3]: ch10-00-generics.html#Listing-10-3
|
||||
|
|
|
@ -24,11 +24,14 @@ to another tweet.
|
|||
We want to make a media aggregator library that can display summaries of data
|
||||
that might be stored in a `NewsArticle` or `Tweet` instance. To do this, we
|
||||
need a summary from each type, and we need to request that summary by calling a
|
||||
`summarize` method on an instance. Listing 10-12 shows the definition of a
|
||||
`summarize` method on an instance. [Listing 10-12][Listing-10-12] shows the definition of a
|
||||
`Summary` trait that expresses this behavior.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-10-12]: #Listing-10-12
|
||||
<a name="Listing-10-12"></a>
|
||||
|
||||
```rust
|
||||
pub trait Summary {
|
||||
fn summarize(&self) -> String;
|
||||
|
@ -55,7 +58,7 @@ one per line and each line ends in a semicolon.
|
|||
### Implementing a Trait on a Type
|
||||
|
||||
Now that we’ve defined the desired behavior using the `Summary` trait, we can
|
||||
implement it on the types in our media aggregator. Listing 10-13 shows an
|
||||
implement it on the types in our media aggregator. [Listing 10-13][Listing-10-13] shows an
|
||||
implementation of the `Summary` trait on the `NewsArticle` struct that uses the
|
||||
headline, the author, and the location to create the return value of
|
||||
`summarize`. For the `Tweet` struct, we define `summarize` as the username
|
||||
|
@ -64,6 +67,9 @@ already limited to 280 characters.
|
|||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-10-13]: #Listing-10-13
|
||||
<a name="Listing-10-13"></a>
|
||||
|
||||
```rust
|
||||
# pub trait Summary {
|
||||
# fn summarize(&self) -> String;
|
||||
|
@ -126,7 +132,7 @@ This code prints `1 new tweet: horse_ebooks: of course, as you probably already
|
|||
know, people`.
|
||||
|
||||
Note that because we defined the `Summary` trait and the `NewsArticle` and
|
||||
`Tweet` types in the same *lib.rs* in Listing 10-13, they’re all in the same
|
||||
`Tweet` types in the same *lib.rs* in [Listing 10-13][Listing-10-13], they’re all in the same
|
||||
scope. Let’s say this *lib.rs* is for a crate we’ve called `aggregator` and
|
||||
someone else wants to use our crate’s functionality to implement the `Summary`
|
||||
trait on a struct defined within their library’s scope. They would need to
|
||||
|
@ -134,7 +140,7 @@ import the trait into their scope first. They would do so by specifying `use
|
|||
aggregator::Summary;`, which then would enable them to implement `Summary` for
|
||||
their type. The `Summary` trait would also need to be a public trait for
|
||||
another crate to implement it, which it is because we put the `pub` keyword
|
||||
before `trait` in Listing 10-12.
|
||||
before `trait` in [Listing 10-12][Listing-10-12].
|
||||
|
||||
One restriction to note with trait implementations is that we can implement a
|
||||
trait on a type only if either the trait or the type is local to our crate.
|
||||
|
@ -161,12 +167,15 @@ in a trait instead of requiring implementations for all methods on every type.
|
|||
Then, as we implement the trait on a particular type, we can keep or override
|
||||
each method’s default behavior.
|
||||
|
||||
Listing 10-14 shows how to specify a default string for the `summarize` method
|
||||
[Listing 10-14][Listing-10-14] shows how to specify a default string for the `summarize` method
|
||||
of the `Summary` trait instead of only defining the method signature, as we did
|
||||
in Listing 10-12.
|
||||
in [Listing 10-12][Listing-10-12].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-10-14]: #Listing-10-14
|
||||
<a name="Listing-10-14"></a>
|
||||
|
||||
```rust
|
||||
pub trait Summary {
|
||||
fn summarize(&self) -> String {
|
||||
|
@ -202,7 +211,7 @@ println!("New article available! {}", article.summarize());
|
|||
This code prints `New article available! (Read more...)`.
|
||||
|
||||
Creating a default implementation for `summarize` doesn’t require us to change
|
||||
anything about the implementation of `Summary` on `Tweet` in Listing 10-13. The
|
||||
anything about the implementation of `Summary` on `Tweet` in [Listing 10-13][Listing-10-13]. The
|
||||
reason is that the syntax for overriding a default implementation is the same
|
||||
as the syntax for implementing a trait method that doesn’t have a default
|
||||
implementation.
|
||||
|
@ -265,7 +274,7 @@ can explore how to use traits with generic type parameters. We can use *trait
|
|||
bounds* to constrain generic types to ensure the type will be limited to those
|
||||
that implement a particular trait and behavior.
|
||||
|
||||
For example, in Listing 10-13, we implemented the `Summary` trait on the types
|
||||
For example, in [Listing 10-13][Listing-10-13], we implemented the `Summary` trait on the types
|
||||
`NewsArticle` and `Tweet`. We can define a function `notify` that calls the
|
||||
`summarize` method on its parameter `item`, which is of the generic type `T`.
|
||||
To be able to call `summarize` on `item` without getting an error telling us
|
||||
|
@ -317,7 +326,7 @@ without lots of trait bounds.
|
|||
### Fixing the `largest` Function with Trait Bounds
|
||||
|
||||
Now that you know how to specify the behavior you want to use using the generic
|
||||
type parameter’s bounds, let’s return to Listing 10-5 to fix the definition of
|
||||
type parameter’s bounds, let’s return to [Listing 10-5][Listing-10-5] to fix the definition of
|
||||
the `largest` function that uses a generic type parameter! Last time we tried
|
||||
to run that code, we received this error:
|
||||
|
||||
|
@ -376,13 +385,16 @@ able to move the value out of `list[0]` and into the `largest` variable,
|
|||
resulting in this error.
|
||||
|
||||
To call this code with only those types that implement the `Copy` trait, we can
|
||||
add `Copy` to the trait bounds of `T`! Listing 10-15 shows the complete code of
|
||||
add `Copy` to the trait bounds of `T`! [Listing 10-15][Listing-10-15] shows the complete code of
|
||||
a generic `largest` function that will compile as long as the types of the
|
||||
values in the slice that we pass into the function implement the `PartialOrd`
|
||||
*and* `Copy` traits, like `i32` and `char` do.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-15]: #Listing-10-15
|
||||
<a name="Listing-10-15"></a>
|
||||
|
||||
```rust
|
||||
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
|
||||
let mut largest = list[0];
|
||||
|
@ -431,11 +443,14 @@ avoid heap allocations. Try implementing these alternate solutions on your own!
|
|||
|
||||
By using a trait bound with an `impl` block that uses generic type parameters,
|
||||
we can implement methods conditionally for types that implement the specified
|
||||
traits. For example, the type `Pair<T>` in Listing 10-16 always implements the
|
||||
traits. For example, the type `Pair<T>` in [Listing 10-16][Listing-10-16] always implements the
|
||||
`new` function. But `Pair<T>` only implements the `cmp_display` method if its
|
||||
inner type `T` implements the `PartialOrd` trait that enables comparison *and*
|
||||
the `Display` trait that enables printing.
|
||||
|
||||
[Listing-10-16]: #Listing-10-16
|
||||
<a name="Listing-10-16"></a>
|
||||
|
||||
```rust
|
||||
use std::fmt::Display;
|
||||
|
||||
|
@ -508,3 +523,10 @@ Another kind of generic that we’ve already been using is called *lifetimes*.
|
|||
Rather than ensuring that a type has the behavior we want, lifetimes ensure
|
||||
that references are valid as long as we need them to be. Let’s look at how
|
||||
lifetimes do that.
|
||||
|
||||
[Listing-10-12]: ch10-02-traits.html#Listing-10-12
|
||||
[Listing-10-13]: ch10-02-traits.html#Listing-10-13
|
||||
[Listing-10-14]: ch10-02-traits.html#Listing-10-14
|
||||
[Listing-10-15]: ch10-02-traits.html#Listing-10-15
|
||||
[Listing-10-16]: ch10-02-traits.html#Listing-10-16
|
||||
[Listing-10-5]: ch10-01-syntax.html#Listing-10-5
|
||||
|
|
|
@ -20,9 +20,12 @@ detailed information.
|
|||
|
||||
The main aim of lifetimes is to prevent dangling references, which cause a
|
||||
program to reference data other than the data it’s intended to reference.
|
||||
Consider the program in Listing 10-17, which has an outer scope and an inner
|
||||
Consider the program in [Listing 10-17][Listing-10-17], which has an outer scope and an inner
|
||||
scope.
|
||||
|
||||
[Listing-10-17]: #Listing-10-17
|
||||
<a name="Listing-10-17"></a>
|
||||
|
||||
```rust,ignore
|
||||
{
|
||||
let r;
|
||||
|
@ -77,8 +80,11 @@ It uses a borrow checker.
|
|||
### The Borrow Checker
|
||||
|
||||
The Rust compiler has a *borrow checker* that compares scopes to determine
|
||||
whether all borrows are valid. Listing 10-18 shows the same code as Listing
|
||||
10-17 but with annotations showing the lifetimes of the variables.
|
||||
whether all borrows are valid. [Listing 10-18][Listing-10-18] shows the same code as [Listing 10-17][Listing-10-17]
|
||||
but with annotations showing the lifetimes of the variables.
|
||||
|
||||
[Listing-10-18]: #Listing-10-18
|
||||
<a name="Listing-10-18"></a>
|
||||
|
||||
```rust,ignore
|
||||
{
|
||||
|
@ -103,9 +109,12 @@ lifetimes and sees that `r` has a lifetime of `'a` but that it refers to memory
|
|||
with a lifetime of `'b`. The program is rejected because `'b` is shorter than
|
||||
`'a`: the subject of the reference doesn’t live as long as the reference.
|
||||
|
||||
Listing 10-19 fixes the code so it doesn’t have a dangling reference and
|
||||
[Listing 10-19][Listing-10-19] fixes the code so it doesn’t have a dangling reference and
|
||||
compiles without any errors.
|
||||
|
||||
[Listing-10-19]: #Listing-10-19
|
||||
<a name="Listing-10-19"></a>
|
||||
|
||||
```rust
|
||||
{
|
||||
let x = 5; // ----------+-- 'b
|
||||
|
@ -132,11 +141,14 @@ lifetimes of parameters and return values in the context of functions.
|
|||
|
||||
Let’s write a function that returns the longer of two string slices. This
|
||||
function will take two string slices and return a string slice. After we’ve
|
||||
implemented the `longest` function, the code in Listing 10-20 should print `The
|
||||
implemented the `longest` function, the code in [Listing 10-20][Listing-10-20] should print `The
|
||||
longest string is abcd`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-20]: #Listing-10-20
|
||||
<a name="Listing-10-20"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let string1 = String::from("abcd");
|
||||
|
@ -157,14 +169,17 @@ type stored in the variable `string1`) as well as string literals (which is
|
|||
what variable `string2` contains).
|
||||
|
||||
Refer to the “String Slices as Parameters” section in Chapter 4 for more
|
||||
discussion about why the parameters we use in Listing 10-20 are the ones we
|
||||
discussion about why the parameters we use in [Listing 10-20][Listing-10-20] are the ones we
|
||||
want.
|
||||
|
||||
If we try to implement the `longest` function as shown in Listing 10-21, it
|
||||
If we try to implement the `longest` function as shown in [Listing 10-21][Listing-10-21], it
|
||||
won’t compile.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-21]: #Listing-10-21
|
||||
<a name="Listing-10-21"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn longest(x: &str, y: &str) -> &str {
|
||||
if x.len() > y.len() {
|
||||
|
@ -251,10 +266,13 @@ parameters inside angle brackets between the function name and the parameter
|
|||
list. The constraint we want to express in this signature is that all the
|
||||
references in the parameters and the return value must have the same lifetime.
|
||||
We’ll name the lifetime `'a` and then add it to each reference, as shown in
|
||||
Listing 10-22.
|
||||
[Listing 10-22][Listing-10-22].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-22]: #Listing-10-22
|
||||
<a name="Listing-10-22"></a>
|
||||
|
||||
```rust
|
||||
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
|
||||
if x.len() > y.len() {
|
||||
|
@ -270,7 +288,7 @@ specifying that all the references in the signature must have the same lifetime
|
|||
`'a`</span>
|
||||
|
||||
This code should compile and produce the result we want when we use it with the
|
||||
`main` function in Listing 10-20.
|
||||
`main` function in [Listing 10-20][Listing-10-20].
|
||||
|
||||
The function signature now tells Rust that for some lifetime `'a`, the function
|
||||
takes two parameters, both of which are string slices that live at least as
|
||||
|
@ -301,11 +319,14 @@ the returned reference will also be valid for the length of the smaller of the
|
|||
lifetimes of `x` and `y`.
|
||||
|
||||
Let’s look at how the lifetime annotations restrict the `longest` function by
|
||||
passing in references that have different concrete lifetimes. Listing 10-23 is
|
||||
passing in references that have different concrete lifetimes. [Listing 10-23][Listing-10-23] is
|
||||
a straightforward example.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-23]: #Listing-10-23
|
||||
<a name="Listing-10-23"></a>
|
||||
|
||||
```rust
|
||||
# fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
|
||||
# if x.len() > y.len() {
|
||||
|
@ -340,11 +361,14 @@ Next, let’s try an example that shows that the lifetime of the reference in
|
|||
declaration of the `result` variable outside the inner scope but leave the
|
||||
assignment of the value to the `result` variable inside the scope with
|
||||
`string2`. Then we’ll move the `println!` that uses `result` outside the inner
|
||||
scope, after the inner scope has ended. The code in Listing 10-24 will not
|
||||
scope, after the inner scope has ended. The code in [Listing 10-24][Listing-10-24] will not
|
||||
compile.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-24]: #Listing-10-24
|
||||
<a name="Listing-10-24"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let string1 = String::from("long string is long");
|
||||
|
@ -387,7 +411,7 @@ still be valid for the `println!` statement. However, the compiler can’t see
|
|||
that the reference is valid in this case. We’ve told Rust that the lifetime of
|
||||
the reference returned by the `longest` function is the same as the smaller of
|
||||
the lifetimes of the references passed in. Therefore, the borrow checker
|
||||
disallows the code in Listing 10-24 as possibly having an invalid reference.
|
||||
disallows the code in [Listing 10-24][Listing-10-24] as possibly having an invalid reference.
|
||||
|
||||
Try designing more experiments that vary the values and lifetimes of the
|
||||
references passed in to the `longest` function and how the returned reference
|
||||
|
@ -472,11 +496,14 @@ would create dangling pointers or otherwise violate memory safety.
|
|||
|
||||
So far, we’ve only defined structs to hold owned types. It’s possible for
|
||||
structs to hold references, but in that case we would need to add a lifetime
|
||||
annotation on every reference in the struct’s definition. Listing 10-25 has a
|
||||
annotation on every reference in the struct’s definition. [Listing 10-25][Listing-10-25] has a
|
||||
struct named `ImportantExcerpt` that holds a string slice.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-10-25]: #Listing-10-25
|
||||
<a name="Listing-10-25"></a>
|
||||
|
||||
```rust
|
||||
struct ImportantExcerpt<'a> {
|
||||
part: &'a str,
|
||||
|
@ -512,11 +539,14 @@ the `ImportantExcerpt` goes out of scope, so the reference in the
|
|||
|
||||
You’ve learned that every reference has a lifetime and that you need to specify
|
||||
lifetime parameters for functions or structs that use references. However, in
|
||||
Chapter 4 we had a function in Listing 4-9, which is shown again in Listing
|
||||
10-26, that compiled without lifetime annotations.
|
||||
Chapter 4 we had a function in [Listing 4-9][Listing-4-9], which is shown again in [Listing 10-26][Listing-10-26],
|
||||
that compiled without lifetime annotations.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-10-26]: #Listing-10-26
|
||||
<a name="Listing-10-26"></a>
|
||||
|
||||
```rust
|
||||
fn first_word(s: &str) -> &str {
|
||||
let bytes = s.as_bytes();
|
||||
|
@ -531,7 +561,7 @@ fn first_word(s: &str) -> &str {
|
|||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 10-26: A function we defined in Listing 4-9 that
|
||||
<span class="caption">Listing 10-26: A function we defined in [Listing 4-9][Listing-4-9] that
|
||||
compiled without lifetime annotations, even though the parameter and return
|
||||
type are references</span>
|
||||
|
||||
|
@ -593,7 +623,7 @@ much nicer to read and write because fewer symbols are necessary.
|
|||
|
||||
Let’s pretend we’re the compiler. We’ll apply these rules to figure out what
|
||||
the lifetimes of the references in the signature of the `first_word` function
|
||||
in Listing 10-26 are. The signature starts without any lifetimes associated
|
||||
in [Listing 10-26][Listing-10-26] are. The signature starts without any lifetimes associated
|
||||
with the references:
|
||||
|
||||
```rust,ignore
|
||||
|
@ -621,7 +651,7 @@ compiler can continue its analysis without needing the programmer to annotate
|
|||
the lifetimes in this function signature.
|
||||
|
||||
Let’s look at another example, this time using the `longest` function that had
|
||||
no lifetime parameters when we started working with it in Listing 10-21:
|
||||
no lifetime parameters when we started working with it in [Listing 10-21][Listing-10-21]:
|
||||
|
||||
```rust,ignore
|
||||
fn longest(x: &str, y: &str) -> &str {
|
||||
|
@ -639,7 +669,7 @@ input lifetime. The third rule doesn’t apply either, because `longest` is a
|
|||
function rather than a method, so none of the parameters are `self`. After
|
||||
working through all three rules, we still haven’t figured out what the return
|
||||
type’s lifetime is. This is why we got an error trying to compile the code in
|
||||
Listing 10-21: the compiler worked through the lifetime elision rules but still
|
||||
[Listing 10-21][Listing-10-21]: the compiler worked through the lifetime elision rules but still
|
||||
couldn’t figure out all the lifetimes of the references in the signature.
|
||||
|
||||
Because the third rule really only applies in method signatures, we’ll look at
|
||||
|
@ -649,7 +679,7 @@ annotate lifetimes in method signatures very often.
|
|||
### Lifetime Annotations in Method Definitions
|
||||
|
||||
When we implement methods on a struct with lifetimes, we use the same syntax as
|
||||
that of generic type parameters shown in Listing 10-11. Where we declare and
|
||||
that of generic type parameters shown in [Listing 10-11][Listing-10-11]. Where we declare and
|
||||
use the lifetime parameters depends on whether they’re related to the struct
|
||||
fields or the method parameters and return values.
|
||||
|
||||
|
@ -661,7 +691,7 @@ In method signatures inside the `impl` block, references might be tied to the
|
|||
lifetime of references in the struct’s fields, or they might be independent. In
|
||||
addition, the lifetime elision rules often make it so that lifetime annotations
|
||||
aren’t necessary in method signatures. Let’s look at some examples using the
|
||||
struct named `ImportantExcerpt` that we defined in Listing 10-25.
|
||||
struct named `ImportantExcerpt` that we defined in [Listing 10-25][Listing-10-25].
|
||||
|
||||
First, we’ll use a method named `level` whose only parameter is a reference to
|
||||
`self` and whose return value is an `i32`, which is not a reference to anything:
|
||||
|
@ -744,7 +774,7 @@ fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a st
|
|||
}
|
||||
```
|
||||
|
||||
This is the `longest` function from Listing 10-22 that returns the longer of
|
||||
This is the `longest` function from [Listing 10-22][Listing-10-22] that returns the longer of
|
||||
two string slices. But now it has an extra parameter named `ann` of the generic
|
||||
type `T`, which can be filled in by any type that implements the `Display`
|
||||
trait as specified by the `where` clause. This extra parameter will be printed
|
||||
|
@ -769,3 +799,16 @@ this chapter: Chapter 17 discusses trait objects, which are another way to use
|
|||
traits. Chapter 19 covers more complex scenarios involving lifetime annotations
|
||||
as well as some advanced type system features. But next, you’ll learn how to
|
||||
write tests in Rust so you can make sure your code is working the way it should.
|
||||
|
||||
[Listing-10-17]: ch10-03-lifetime-syntax.html#Listing-10-17
|
||||
[Listing-10-18]: ch10-03-lifetime-syntax.html#Listing-10-18
|
||||
[Listing-10-19]: ch10-03-lifetime-syntax.html#Listing-10-19
|
||||
[Listing-10-20]: ch10-03-lifetime-syntax.html#Listing-10-20
|
||||
[Listing-10-21]: ch10-03-lifetime-syntax.html#Listing-10-21
|
||||
[Listing-10-22]: ch10-03-lifetime-syntax.html#Listing-10-22
|
||||
[Listing-10-23]: ch10-03-lifetime-syntax.html#Listing-10-23
|
||||
[Listing-10-24]: ch10-03-lifetime-syntax.html#Listing-10-24
|
||||
[Listing-10-25]: ch10-03-lifetime-syntax.html#Listing-10-25
|
||||
[Listing-10-26]: ch10-03-lifetime-syntax.html#Listing-10-26
|
||||
[Listing-4-9]: ch04-03-slices.html#Listing-4-9
|
||||
[Listing-10-11]: ch10-01-syntax.html#Listing-10-11
|
||||
|
|
|
@ -43,10 +43,13 @@ $ cd adder
|
|||
```
|
||||
|
||||
The contents of the *src/lib.rs* file in your `adder` library should look like
|
||||
Listing 11-1.
|
||||
[Listing 11-1][Listing-11-1].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-11-1]: #Listing-11-1
|
||||
<a name="Listing-11-1"></a>
|
||||
|
||||
```rust
|
||||
# fn main() {}
|
||||
#[cfg(test)]
|
||||
|
@ -72,8 +75,10 @@ The function body uses the `assert_eq!` macro to assert that 2 + 2 equals 4.
|
|||
This assertion serves as an example of the format for a typical test. Let’s run
|
||||
it to see that this test passes.
|
||||
|
||||
The `cargo test` command runs all tests in our project, as shown in Listing
|
||||
11-2.
|
||||
The `cargo test` command runs all tests in our project, as shown in [Listing 11-2][Listing-11-2].
|
||||
|
||||
[Listing-11-2]: #Listing-11-2
|
||||
<a name="Listing-11-2"></a>
|
||||
|
||||
```text
|
||||
$ cargo test
|
||||
|
@ -153,10 +158,13 @@ when something in the test function panics. Each test is run in a new thread,
|
|||
and when the main thread sees that a test thread has died, the test is marked
|
||||
as failed. We talked about the simplest way to cause a panic in Chapter 9,
|
||||
which is to call the `panic!` macro. Enter the new test, `another`, so your
|
||||
*src/lib.rs* file looks like Listing 11-3.
|
||||
*src/lib.rs* file looks like [Listing 11-3][Listing-11-3].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-11-3]: #Listing-11-3
|
||||
<a name="Listing-11-3"></a>
|
||||
|
||||
```rust
|
||||
# fn main() {}
|
||||
#[cfg(test)]
|
||||
|
@ -176,8 +184,11 @@ mod tests {
|
|||
<span class="caption">Listing 11-3: Adding a second test that will fail because
|
||||
we call the `panic!` macro</span>
|
||||
|
||||
Run the tests again using `cargo test`. The output should look like Listing
|
||||
11-4, which shows that our `exploration` test passed and `another` failed.
|
||||
Run the tests again using `cargo test`. The output should look like [Listing 11-4][Listing-11-4],
|
||||
which shows that our `exploration` test passed and `another` failed.
|
||||
|
||||
[Listing-11-4]: #Listing-11-4
|
||||
<a name="Listing-11-4"></a>
|
||||
|
||||
```text
|
||||
running 2 tests
|
||||
|
@ -227,12 +238,15 @@ the `assert!` macro calls the `panic!` macro, which causes the test to fail.
|
|||
Using the `assert!` macro helps us check that our code is functioning in the
|
||||
way we intend.
|
||||
|
||||
In Chapter 5, Listing 5-15, we used a `Rectangle` struct and a `can_hold`
|
||||
method, which are repeated here in Listing 11-5. Let’s put this code in the
|
||||
In Chapter 5, [Listing 5-15][Listing-5-15], we used a `Rectangle` struct and a `can_hold`
|
||||
method, which are repeated here in [Listing 11-5][Listing-11-5]. Let’s put this code in the
|
||||
*src/lib.rs* file and write some tests for it using the `assert!` macro.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-11-5]: #Listing-11-5
|
||||
<a name="Listing-11-5"></a>
|
||||
|
||||
```rust
|
||||
# fn main() {}
|
||||
#[derive(Debug)]
|
||||
|
@ -252,13 +266,16 @@ impl Rectangle {
|
|||
`can_hold` method from Chapter 5</span>
|
||||
|
||||
The `can_hold` method returns a Boolean, which means it’s a perfect use case
|
||||
for the `assert!` macro. In Listing 11-6, we write a test that exercises the
|
||||
`can_hold` method by creating a `Rectangle` instance that has a width of 8 and
|
||||
a height of 7 and asserting that it can hold another `Rectangle` instance that
|
||||
has a width of 5 and a height of 1.
|
||||
for the `assert!` macro. In [Listing 11-6][Listing-11-6], we write a test that exercises the
|
||||
`can_hold` method by creating a `Rectangle` instance that has a length of 8 and
|
||||
a width of 7 and asserting that it can hold another `Rectangle` instance that
|
||||
has a length of 5 and a width of 1.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-11-6]: #Listing-11-6
|
||||
<a name="Listing-11-6"></a>
|
||||
|
||||
```rust
|
||||
# fn main() {}
|
||||
#[cfg(test)]
|
||||
|
@ -393,12 +410,15 @@ fails, which makes it easier to see *why* the test failed; conversely, the
|
|||
`assert!` macro only indicates that it got a `false` value for the `==`
|
||||
expression, not the values that lead to the `false` value.
|
||||
|
||||
In Listing 11-7, we write a function named `add_two` that adds `2` to its
|
||||
In [Listing 11-7][Listing-11-7], we write a function named `add_two` that adds `2` to its
|
||||
parameter and returns the result. Then we test this function using the
|
||||
`assert_eq!` macro.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-11-7]: #Listing-11-7
|
||||
<a name="Listing-11-7"></a>
|
||||
|
||||
```rust
|
||||
# fn main() {}
|
||||
pub fn add_two(a: i32) -> i32 {
|
||||
|
@ -494,7 +514,7 @@ of the standard library types implement these traits. For structs and enums
|
|||
that you define, you’ll need to implement `PartialEq` to assert that values of
|
||||
those types are equal or not equal. You’ll need to implement `Debug` to print
|
||||
the values when the assertion fails. Because both traits are derivable traits,
|
||||
as mentioned in Listing 5-12 in Chapter 5, this is usually as straightforward
|
||||
as mentioned in [Listing 5-12][Listing-5-12] in Chapter 5, this is usually as straightforward
|
||||
as adding the `#[derive(PartialEq, Debug)]` annotation to your struct or enum
|
||||
definition. See Appendix C for more details about these and other derivable
|
||||
traits.
|
||||
|
@ -602,7 +622,7 @@ debug what happened instead of what we were expecting to happen.
|
|||
In addition to checking that our code returns the correct values we expect,
|
||||
it’s also important to check that our code handles error conditions as we
|
||||
expect. For example, consider the `Guess` type that we created in Chapter 9,
|
||||
Listing 9-9. Other code that uses `Guess` depends on the guarantee that `Guess`
|
||||
[Listing 9-9][Listing-9-9]. Other code that uses `Guess` depends on the guarantee that `Guess`
|
||||
instances will contain only values between 1 and 100. We can write a test that
|
||||
ensures that attempting to create a `Guess` instance with a value outside that
|
||||
range panics.
|
||||
|
@ -611,11 +631,14 @@ We do this by adding another attribute, `should_panic`, to our test function.
|
|||
This attribute makes a test pass if the code inside the function panics; the
|
||||
test will fail if the code inside the function doesn’t panic.
|
||||
|
||||
Listing 11-8 shows a test that checks that the error conditions of `Guess::new`
|
||||
[Listing 11-8][Listing-11-8] shows a test that checks that the error conditions of `Guess::new`
|
||||
happen when we expect them to.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-11-8]: #Listing-11-8
|
||||
<a name="Listing-11-8"></a>
|
||||
|
||||
```rust
|
||||
# fn main() {}
|
||||
pub struct Guess {
|
||||
|
@ -684,7 +707,7 @@ impl Guess {
|
|||
}
|
||||
```
|
||||
|
||||
When we run the test in Listing 11-8, it will fail:
|
||||
When we run the test in [Listing 11-8][Listing-11-8], it will fail:
|
||||
|
||||
```text
|
||||
running 1 test
|
||||
|
@ -708,11 +731,14 @@ test panics for a different reason than the one we were expecting to happen. To
|
|||
make `should_panic` tests more precise, we can add an optional `expected`
|
||||
parameter to the `should_panic` attribute. The test harness will make sure that
|
||||
the failure message contains the provided text. For example, consider the
|
||||
modified code for `Guess` in Listing 11-9 where the `new` function panics with
|
||||
modified code for `Guess` in [Listing 11-9][Listing-11-9] where the `new` function panics with
|
||||
different messages depending on whether the value is too small or too large.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-11-9]: #Listing-11-9
|
||||
<a name="Listing-11-9"></a>
|
||||
|
||||
```rust
|
||||
# fn main() {}
|
||||
# pub struct Guess {
|
||||
|
@ -804,3 +830,16 @@ figuring out where our bug is!
|
|||
Now that you know several ways to write tests, let’s look at what is happening
|
||||
when we run our tests and explore the different options we can use with `cargo
|
||||
test`.
|
||||
|
||||
[Listing-5-12]: ch05-02-example-structs.html#Listing-5-12
|
||||
[Listing-5-15]: ch05-03-method-syntax.html#Listing-5-15
|
||||
[Listing-11-1]: ch11-01-writing-tests.html#Listing-11-1
|
||||
[Listing-11-2]: ch11-01-writing-tests.html#Listing-11-2
|
||||
[Listing-11-3]: ch11-01-writing-tests.html#Listing-11-3
|
||||
[Listing-11-4]: ch11-01-writing-tests.html#Listing-11-4
|
||||
[Listing-11-5]: ch11-01-writing-tests.html#Listing-11-5
|
||||
[Listing-11-6]: ch11-01-writing-tests.html#Listing-11-6
|
||||
[Listing-11-7]: ch11-01-writing-tests.html#Listing-11-7
|
||||
[Listing-11-8]: ch11-01-writing-tests.html#Listing-11-8
|
||||
[Listing-11-9]: ch11-01-writing-tests.html#Listing-11-9
|
||||
[Listing-9-9]: ch09-03-to-panic-or-not-to-panic.html#Listing-9-9
|
||||
|
|
|
@ -56,11 +56,14 @@ passes, we won’t see the `println!` output in the terminal; we’ll see only t
|
|||
line that indicates the test passed. If a test fails, we’ll see whatever was
|
||||
printed to standard output with the rest of the failure message.
|
||||
|
||||
As an example, Listing 11-10 has a silly function that prints the value of its
|
||||
As an example, [Listing 11-10][Listing-11-10] has a silly function that prints the value of its
|
||||
parameter and returns 10, as well as a test that passes and a test that fails.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-11-10]: #Listing-11-10
|
||||
<a name="Listing-11-10"></a>
|
||||
|
||||
```rust
|
||||
fn prints_and_returns_10(a: i32) -> i32 {
|
||||
println!("I got the value {}", a);
|
||||
|
@ -122,7 +125,7 @@ output capture behavior by using the `--nocapture` flag:
|
|||
$ cargo test -- --nocapture
|
||||
```
|
||||
|
||||
When we run the tests in Listing 11-10 again with the `--nocapture` flag, we
|
||||
When we run the tests in [Listing 11-10][Listing-11-10] again with the `--nocapture` flag, we
|
||||
see the following output:
|
||||
|
||||
```text
|
||||
|
@ -157,10 +160,13 @@ that code. You can choose which tests to run by passing `cargo test` the name
|
|||
or names of the test(s) you want to run as an argument.
|
||||
|
||||
To demonstrate how to run a subset of tests, we’ll create three tests for our
|
||||
`add_two` function, as shown in Listing 11-11, and choose which ones to run.
|
||||
`add_two` function, as shown in [Listing 11-11][Listing-11-11], and choose which ones to run.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-11-11]: #Listing-11-11
|
||||
<a name="Listing-11-11"></a>
|
||||
|
||||
```rust
|
||||
pub fn add_two(a: i32) -> i32 {
|
||||
a + 2
|
||||
|
@ -304,3 +310,6 @@ By controlling which tests run, you can make sure your `cargo test` results
|
|||
will be fast. When you’re at a point where it makes sense to check the results
|
||||
of the `ignored` tests and you have time to wait for the results, you can run
|
||||
`cargo test -- --ignored` instead.
|
||||
|
||||
[Listing-11-10]: ch11-02-running-tests.html#Listing-11-10
|
||||
[Listing-11-11]: ch11-02-running-tests.html#Listing-11-11
|
||||
|
|
|
@ -62,10 +62,13 @@ There’s debate within the testing community about whether or not private
|
|||
functions should be tested directly, and other languages make it difficult or
|
||||
impossible to test private functions. Regardless of which testing ideology you
|
||||
adhere to, Rust’s privacy rules do allow you to test private functions.
|
||||
Consider the code in Listing 11-12 with the private function `internal_adder`.
|
||||
Consider the code in [Listing 11-12][Listing-11-12] with the private function `internal_adder`.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-11-12]: #Listing-11-12
|
||||
<a name="Listing-11-12"></a>
|
||||
|
||||
```rust
|
||||
pub fn add_two(a: i32) -> i32 {
|
||||
internal_adder(a, 2)
|
||||
|
@ -111,12 +114,15 @@ to *src*. Cargo knows to look for integration test files in this directory. We
|
|||
can then make as many test files as we want to in this directory, and Cargo
|
||||
will compile each of the files as an individual crate.
|
||||
|
||||
Let’s create an integration test. With the code in Listing 11-12 still in the
|
||||
Let’s create an integration test. With the code in [Listing 11-12][Listing-11-12] still in the
|
||||
*src/lib.rs* file, make a *tests* directory, create a new file named
|
||||
*tests/integration_test.rs*, and enter the code in Listing 11-13.
|
||||
*tests/integration_test.rs*, and enter the code in [Listing 11-13][Listing-11-13].
|
||||
|
||||
<span class="filename">Filename: tests/integration_test.rs</span>
|
||||
|
||||
[Listing-11-13]: #Listing-11-13
|
||||
<a name="Listing-11-13"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate adder;
|
||||
|
||||
|
@ -165,7 +171,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
|
|||
The three sections of output include the unit tests, the integration test, and
|
||||
the doc tests. The first section for the unit tests is the same as we’ve been
|
||||
seeing: one line for each unit test (one named `internal` that we added in
|
||||
Listing 11-12) and then a summary line for the unit tests.
|
||||
[Listing 11-12][Listing-11-12]) and then a summary line for the unit tests.
|
||||
|
||||
The integration tests section starts with the line `Running
|
||||
target/debug/deps/integration_test-ce99bcc2479f4607` (the hash at the end of
|
||||
|
@ -290,7 +296,7 @@ fn it_adds_two() {
|
|||
```
|
||||
|
||||
Note that the `mod common;` declaration is the same as the module declarations
|
||||
we demonstrated in Listing 7-4. Then in the test function, we can call the
|
||||
we demonstrated in [Listing 7-4][Listing-7-4]. Then in the test function, we can call the
|
||||
`common::setup()` function.
|
||||
|
||||
#### Integration Tests for Binary Crates
|
||||
|
@ -322,3 +328,7 @@ reduce logic bugs having to do with how your code is expected to behave.
|
|||
|
||||
Let’s combine the knowledge you learned in this chapter and in previous
|
||||
chapters to work on a project!
|
||||
|
||||
[Listing-7-4]: ch07-01-mod-and-the-filesystem.html#Listing-7-4
|
||||
[Listing-11-12]: ch11-03-test-organization.html#Listing-11-12
|
||||
[Listing-11-13]: ch11-03-test-organization.html#Listing-11-13
|
||||
|
|
|
@ -35,11 +35,14 @@ details about iterators: iterators produce a series of values, and we can call
|
|||
the `collect` method on an iterator to turn it into a collection, such as a
|
||||
vector, containing all the elements the iterator produces.
|
||||
|
||||
Use the code in Listing 12-1 to allow your `minigrep` program to read any
|
||||
Use the code in [Listing 12-1][Listing-12-1] to allow your `minigrep` program to read any
|
||||
command line arguments passed to it and then collect the values into a vector.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-1]: #Listing-12-1
|
||||
<a name="Listing-12-1"></a>
|
||||
|
||||
```rust
|
||||
use std::env;
|
||||
|
||||
|
@ -105,10 +108,13 @@ chapter, we’ll ignore it and save only the two arguments we need.
|
|||
Printing the value of the vector of arguments illustrated that the program is
|
||||
able to access the values specified as command line arguments. Now we need to
|
||||
save the values of the two arguments in variables so we can use the values
|
||||
throughout the rest of the program. We do that in Listing 12-2.
|
||||
throughout the rest of the program. We do that in [Listing 12-2][Listing-12-2].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-2]: #Listing-12-2
|
||||
<a name="Listing-12-2"></a>
|
||||
|
||||
```rust,should_panic
|
||||
use std::env;
|
||||
|
||||
|
@ -151,3 +157,6 @@ saved into the right variables. Later we’ll add some error handling to deal
|
|||
with certain potential erroneous situations, such as when the user provides no
|
||||
arguments; for now, we’ll ignore that situation and work on adding file-reading
|
||||
capabilities instead.
|
||||
|
||||
[Listing-12-1]: ch12-01-accepting-command-line-arguments.html#Listing-12-1
|
||||
[Listing-12-2]: ch12-01-accepting-command-line-arguments.html#Listing-12-2
|
||||
|
|
|
@ -3,13 +3,16 @@
|
|||
Now we’ll add functionality to read the file that is specified in the
|
||||
`filename` command line argument. First, we need a sample file to test it with:
|
||||
the best kind of file to use to make sure `minigrep` is working is one with a
|
||||
small amount of text over multiple lines with some repeated words. Listing 12-3
|
||||
small amount of text over multiple lines with some repeated words. [Listing 12-3][Listing-12-3]
|
||||
has an Emily Dickinson poem that will work well! Create a file called
|
||||
*poem.txt* at the root level of your project, and enter the poem “I’m Nobody!
|
||||
Who are you?”
|
||||
|
||||
<span class="filename">Filename: poem.txt</span>
|
||||
|
||||
[Listing-12-3]: #Listing-12-3
|
||||
<a name="Listing-12-3"></a>
|
||||
|
||||
```text
|
||||
I'm nobody! Who are you?
|
||||
Are you nobody, too?
|
||||
|
@ -26,10 +29,13 @@ To an admiring bog!
|
|||
case</span>
|
||||
|
||||
With the text in place, edit *src/main.rs* and add code to open the file, as
|
||||
shown in Listing 12-4.
|
||||
shown in [Listing 12-4][Listing-12-4].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-4]: #Listing-12-4
|
||||
<a name="Listing-12-4"></a>
|
||||
|
||||
```rust,should_panic
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
|
@ -109,3 +115,6 @@ as we could. The program is still small, so these flaws aren’t a big problem,
|
|||
but as the program grows, it will be harder to fix them cleanly. It’s good
|
||||
practice to begin refactoring early on when developing a program, because it’s
|
||||
much easier to refactor smaller amounts of code. We’ll do that next.
|
||||
|
||||
[Listing-12-3]: ch12-02-reading-a-file.html#Listing-12-3
|
||||
[Listing-12-4]: ch12-02-reading-a-file.html#Listing-12-4
|
||||
|
|
|
@ -69,11 +69,14 @@ reading it. Let’s rework our program by following this process.
|
|||
|
||||
We’ll extract the functionality for parsing arguments into a function that
|
||||
`main` will call to prepare for moving the command line parsing logic to
|
||||
*src/lib.rs*. Listing 12-5 shows the new start of `main` that calls a new
|
||||
*src/lib.rs*. [Listing 12-5][Listing-12-5] shows the new start of `main` that calls a new
|
||||
function `parse_config`, which we’ll define in *src/main.rs* for the moment.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-5]: #Listing-12-5
|
||||
<a name="Listing-12-5"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
@ -128,10 +131,13 @@ other and what their purpose is.
|
|||
> Note: Some people call this anti-pattern of using primitive values when a
|
||||
> complex type would be more appropriate *primitive obsession*.
|
||||
|
||||
Listing 12-6 shows the improvements to the `parse_config` function.
|
||||
[Listing 12-6][Listing-12-6] shows the improvements to the `parse_config` function.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-6]: #Listing-12-6
|
||||
<a name="Listing-12-6"></a>
|
||||
|
||||
```rust,should_panic
|
||||
# use std::env;
|
||||
# use std::fs::File;
|
||||
|
@ -220,11 +226,14 @@ named `new` that is associated with the `Config` struct. Making this change
|
|||
will make the code more idiomatic. We can create instances of types in the
|
||||
standard library, such as `String`, by calling `String::new`. Similarly, by
|
||||
changing `parse_config` into a `new` function associated with `Config`, we’ll
|
||||
be able to create instances of `Config` by calling `Config::new`. Listing 12-7
|
||||
be able to create instances of `Config` by calling `Config::new`. [Listing 12-7][Listing-12-7]
|
||||
shows the changes we need to make.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-7]: #Listing-12-7
|
||||
<a name="Listing-12-7"></a>
|
||||
|
||||
```rust,should_panic
|
||||
# use std::env;
|
||||
#
|
||||
|
@ -284,13 +293,16 @@ happened and what they should do instead. Let’s fix that now.
|
|||
|
||||
#### Improving the Error Message
|
||||
|
||||
In Listing 12-8, we add a check in the `new` function that will verify that the
|
||||
In [Listing 12-8][Listing-12-8], we add a check in the `new` function that will verify that the
|
||||
slice is long enough before accessing index 1 and 2. If the slice isn’t long
|
||||
enough, the program panics and displays a better error message than the `index
|
||||
out of bounds` message.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-8]: #Listing-12-8
|
||||
<a name="Listing-12-8"></a>
|
||||
|
||||
```rust,ignore
|
||||
// --snip--
|
||||
fn new(args: &[String]) -> Config {
|
||||
|
@ -303,7 +315,7 @@ fn new(args: &[String]) -> Config {
|
|||
<span class="caption">Listing 12-8: Adding a check for the number of
|
||||
arguments</span>
|
||||
|
||||
This code is similar to the `Guess::new` function we wrote in Listing 9-9,
|
||||
This code is similar to the `Guess::new` function we wrote in [Listing 9-9][Listing-9-9],
|
||||
where we called `panic!` when the `value` argument was out of the range of
|
||||
valid values. Instead of checking for a range of values here, we’re checking
|
||||
that the length of `args` is at least 3 and the rest of the function can
|
||||
|
@ -325,7 +337,7 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace.
|
|||
|
||||
This output is better: we now have a reasonable error message. However, we also
|
||||
have extraneous information we don’t want to give to our users. Perhaps using
|
||||
the technique we used in Listing 9-9 isn’t the best to use here: a call to
|
||||
the technique we used in [Listing 9-9][Listing-9-9] isn’t the best to use here: a call to
|
||||
`panic!` is more appropriate for a programming problem than a usage problem, as
|
||||
discussed in Chapter 9. Instead, we can use the other technique you learned
|
||||
about in Chapter 9—returning a `Result` that indicates either success or an
|
||||
|
@ -340,13 +352,16 @@ signal there was a problem. Then we can change `main` to convert an `Err`
|
|||
variant into a more practical error for our users without the surrounding text
|
||||
about `thread 'main'` and `RUST_BACKTRACE` that a call to `panic!` causes.
|
||||
|
||||
Listing 12-9 shows the changes we need to make to the return value of
|
||||
[Listing 12-9][Listing-12-9] shows the changes we need to make to the return value of
|
||||
`Config::new` and the body of the function needed to return a `Result`. Note
|
||||
that this won’t compile until we update `main` as well, which we’ll do in the
|
||||
next listing.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-9]: #Listing-12-9
|
||||
<a name="Listing-12-9"></a>
|
||||
|
||||
```rust,ignore
|
||||
impl Config {
|
||||
fn new(args: &[String]) -> Result<Config, &'static str> {
|
||||
|
@ -383,13 +398,16 @@ more cleanly in the error case.
|
|||
|
||||
To handle the error case and print a user-friendly message, we need to update
|
||||
`main` to handle the `Result` being returned by `Config::new`, as shown in
|
||||
Listing 12-10. We’ll also take the responsibility of exiting the command line
|
||||
[Listing 12-10][Listing-12-10]. We’ll also take the responsibility of exiting the command line
|
||||
tool with a nonzero error code from `panic!` and implement it by hand. A
|
||||
nonzero exit status is a convention to signal to the process that called our
|
||||
program that the program exited with an error state.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-10]: #Listing-12-10
|
||||
<a name="Listing-12-10"></a>
|
||||
|
||||
```rust,ignore
|
||||
use std::process;
|
||||
|
||||
|
@ -416,7 +434,7 @@ is an `Err` value, this method calls the code in the *closure*, which is an
|
|||
anonymous function we define and pass as an argument to `unwrap_or_else`. We’ll
|
||||
cover closures in more detail in Chapter 13. For now, you just need to know
|
||||
that `unwrap_or_else` will pass the inner value of the `Err`, which in this
|
||||
case is the static string `not enough arguments` that we added in Listing 12-9,
|
||||
case is the static string `not enough arguments` that we added in [Listing 12-9][Listing-12-9],
|
||||
to our closure in the argument `err` that appears between the vertical pipes.
|
||||
The code in the closure can then use the `err` value when it runs.
|
||||
|
||||
|
@ -425,7 +443,7 @@ code in the closure that will be run in the error case is only two lines: we
|
|||
print the `err` value and then call `process::exit`. The `process::exit`
|
||||
function will stop the program immediately and return the number that was
|
||||
passed as the exit status code. This is similar to the `panic!`-based handling
|
||||
we used in Listing 12-8, but we no longer get all the extra output. Let’s try
|
||||
we used in [Listing 12-8][Listing-12-8], but we no longer get all the extra output. Let’s try
|
||||
it:
|
||||
|
||||
```text
|
||||
|
@ -448,12 +466,15 @@ configuration or handling errors. When we’re done, `main` will be concise and
|
|||
easy to verify by inspection, and we’ll be able to write tests for all the
|
||||
other logic.
|
||||
|
||||
Listing 12-11 shows the extracted `run` function. For now, we’re just making
|
||||
[Listing 12-11][Listing-12-11] shows the extracted `run` function. For now, we’re just making
|
||||
the small, incremental improvement of extracting the function. We’re still
|
||||
defining the function in *src/main.rs*.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-11]: #Listing-12-11
|
||||
<a name="Listing-12-11"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
// --snip--
|
||||
|
@ -487,15 +508,18 @@ argument.
|
|||
#### Returning Errors from the `run` Function
|
||||
|
||||
With the remaining program logic separated into the `run` function, we can
|
||||
improve the error handling, as we did with `Config::new` in Listing 12-9.
|
||||
improve the error handling, as we did with `Config::new` in [Listing 12-9][Listing-12-9].
|
||||
Instead of allowing the program to panic by calling `expect`, the `run`
|
||||
function will return a `Result<T, E>` when something goes wrong. This will let
|
||||
us further consolidate into `main` the logic around handling errors in a
|
||||
user-friendly way. Listing 12-12 shows the changes we need to make to the
|
||||
user-friendly way. [Listing 12-12][Listing-12-12] shows the changes we need to make to the
|
||||
signature and body of `run`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-12]: #Listing-12-12
|
||||
<a name="Listing-12-12"></a>
|
||||
|
||||
```rust,ignore
|
||||
use std::error::Error;
|
||||
|
||||
|
@ -559,7 +583,7 @@ have some error-handling code here! Let’s rectify that problem now.
|
|||
#### Handling Errors Returned from `run` in `main`
|
||||
|
||||
We’ll check for errors and handle them using a technique similar to one we used
|
||||
with `Config::new` in Listing 12-10, but with a slight difference:
|
||||
with `Config::new` in [Listing 12-10][Listing-12-10], but with a slight difference:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
|
@ -602,12 +626,15 @@ Let’s move all the code that isn’t the `main` function from *src/main.rs* to
|
|||
* The definition of `Config`
|
||||
* The `Config::new` function definition
|
||||
|
||||
The contents of *src/lib.rs* should have the signatures shown in Listing 12-13
|
||||
The contents of *src/lib.rs* should have the signatures shown in [Listing 12-13][Listing-12-13]
|
||||
(we’ve omitted the bodies of the functions for brevity). Note that this won’t
|
||||
compile until we modify *src/main.rs* in Listing 12-14.
|
||||
compile until we modify *src/main.rs* in [Listing 12-14][Listing-12-14].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-12-13]: #Listing-12-13
|
||||
<a name="Listing-12-13"></a>
|
||||
|
||||
```rust,ignore
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
|
@ -637,10 +664,13 @@ We’ve made liberal use of the `pub` keyword: on `Config`, on its fields and it
|
|||
public API that we can test!
|
||||
|
||||
Now we need to bring the code we moved to *src/lib.rs* into the scope of the
|
||||
binary crate in *src/main.rs*, as shown in Listing 12-14.
|
||||
binary crate in *src/main.rs*, as shown in [Listing 12-14][Listing-12-14].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-14]: #Listing-12-14
|
||||
<a name="Listing-12-14"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate minigrep;
|
||||
|
||||
|
@ -673,3 +703,15 @@ modular. Almost all of our work will be done in *src/lib.rs* from here on out.
|
|||
Let’s take advantage of this newfound modularity by doing something that would
|
||||
have been difficult with the old code but is easy with the new code: we’ll
|
||||
write some tests!
|
||||
|
||||
[Listing-12-5]: ch12-03-improving-error-handling-and-modularity.html#Listing-12-5
|
||||
[Listing-12-6]: ch12-03-improving-error-handling-and-modularity.html#Listing-12-6
|
||||
[Listing-12-7]: ch12-03-improving-error-handling-and-modularity.html#Listing-12-7
|
||||
[Listing-12-8]: ch12-03-improving-error-handling-and-modularity.html#Listing-12-8
|
||||
[Listing-12-9]: ch12-03-improving-error-handling-and-modularity.html#Listing-12-9
|
||||
[Listing-12-10]: ch12-03-improving-error-handling-and-modularity.html#Listing-12-10
|
||||
[Listing-12-11]: ch12-03-improving-error-handling-and-modularity.html#Listing-12-11
|
||||
[Listing-12-12]: ch12-03-improving-error-handling-and-modularity.html#Listing-12-12
|
||||
[Listing-12-13]: ch12-03-improving-error-handling-and-modularity.html#Listing-12-13
|
||||
[Listing-12-14]: ch12-03-improving-error-handling-and-modularity.html#Listing-12-14
|
||||
[Listing-9-9]: ch09-03-to-panic-or-not-to-panic.html#Listing-9-9
|
||||
|
|
|
@ -35,10 +35,13 @@ Then, in *src/lib.rs*, we’ll add a `test` module with a test function, as we
|
|||
did in Chapter 11. The test function specifies the behavior we want the
|
||||
`search` function to have: it will take a query and the text to search for the
|
||||
query in, and it will return only the lines from the text that contain the
|
||||
query. Listing 12-15 shows this test, which won’t compile yet.
|
||||
query. [Listing 12-15][Listing-12-15] shows this test, which won’t compile yet.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-12-15]: #Listing-12-15
|
||||
<a name="Listing-12-15"></a>
|
||||
|
||||
```rust
|
||||
# fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
# vec![]
|
||||
|
@ -74,12 +77,15 @@ from the `search` function contains only the line we expect.
|
|||
We aren’t able to run this test and watch it fail because the test doesn’t even
|
||||
compile: the `search` function doesn’t exist yet! So now we’ll add just enough
|
||||
code to get the test to compile and run by adding a definition of the `search`
|
||||
function that always returns an empty vector, as shown in Listing 12-16. Then
|
||||
function that always returns an empty vector, as shown in [Listing 12-16][Listing-12-16]. Then
|
||||
the test should compile and fail because an empty vector doesn’t match a vector
|
||||
containing the line `"safe, fast, productive."`
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-12-16]: #Listing-12-16
|
||||
<a name="Listing-12-16"></a>
|
||||
|
||||
```rust
|
||||
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
vec![]
|
||||
|
@ -176,11 +182,14 @@ Let’s work through each step, starting with iterating through lines.
|
|||
#### Iterating Through Lines with the `lines` Method
|
||||
|
||||
Rust has a helpful method to handle line-by-line iteration of strings,
|
||||
conveniently named `lines`, that works as shown in Listing 12-17. Note this
|
||||
conveniently named `lines`, that works as shown in [Listing 12-17][Listing-12-17]. Note this
|
||||
won’t compile yet.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-12-17]: #Listing-12-17
|
||||
<a name="Listing-12-17"></a>
|
||||
|
||||
```rust,ignore
|
||||
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
for line in contents.lines() {
|
||||
|
@ -193,8 +202,8 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
|||
</span>
|
||||
|
||||
The `lines` method returns an iterator. We’ll talk about iterators in depth in
|
||||
Chapter 13, but recall that you saw this way of using an iterator in Listing
|
||||
3-5, where we used a `for` loop with an iterator to run some code on each item
|
||||
Chapter 13, but recall that you saw this way of using an iterator in [Listing 3-5][Listing-3-5],
|
||||
where we used a `for` loop with an iterator to run some code on each item
|
||||
in a collection.
|
||||
|
||||
#### Searching Each Line for the Query
|
||||
|
@ -202,10 +211,13 @@ in a collection.
|
|||
Next, we’ll check whether the current line contains our query string.
|
||||
Fortunately, strings have a helpful method named `contains` that does this for
|
||||
us! Add a call to the `contains` method in the `search` function, as shown in
|
||||
Listing 12-18. Note this still won’t compile yet.
|
||||
[Listing 12-18][Listing-12-18]. Note this still won’t compile yet.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-12-18]: #Listing-12-18
|
||||
<a name="Listing-12-18"></a>
|
||||
|
||||
```rust,ignore
|
||||
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
for line in contents.lines() {
|
||||
|
@ -224,10 +236,13 @@ line contains the string in `query`</span>
|
|||
We also need a way to store the lines that contain our query string. For that,
|
||||
we can make a mutable vector before the `for` loop and call the `push` method
|
||||
to store a `line` in the vector. After the `for` loop, we return the vector, as
|
||||
shown in Listing 12-19.
|
||||
shown in [Listing 12-19][Listing-12-19].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-12-19]: #Listing-12-19
|
||||
<a name="Listing-12-19"></a>
|
||||
|
||||
```rust,ignore
|
||||
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
let mut results = Vec::new();
|
||||
|
@ -330,3 +345,10 @@ and output, lifetimes, testing, and command line parsing.
|
|||
To round out this project, we’ll briefly demonstrate how to work with
|
||||
environment variables and how to print to standard error, both of which are
|
||||
useful when you’re writing command line programs.
|
||||
|
||||
[Listing-3-5]: ch03-05-control-flow.html#Listing-3-5
|
||||
[Listing-12-15]: ch12-04-testing-the-librarys-functionality.html#Listing-12-15
|
||||
[Listing-12-16]: ch12-04-testing-the-librarys-functionality.html#Listing-12-16
|
||||
[Listing-12-17]: ch12-04-testing-the-librarys-functionality.html#Listing-12-17
|
||||
[Listing-12-18]: ch12-04-testing-the-librarys-functionality.html#Listing-12-18
|
||||
[Listing-12-19]: ch12-04-testing-the-librarys-functionality.html#Listing-12-19
|
||||
|
|
|
@ -14,10 +14,13 @@ the environment variable is on. We’ll continue to follow the TDD process, so
|
|||
the first step is again to write a failing test. We’ll add a new test for the
|
||||
new `search_case_insensitive` function and rename our old test from
|
||||
`one_result` to `case_sensitive` to clarify the differences between the two
|
||||
tests, as shown in Listing 12-20.
|
||||
tests, as shown in [Listing 12-20][Listing-12-20].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-12-20]: #Listing-12-20
|
||||
<a name="Listing-12-20"></a>
|
||||
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
@ -72,17 +75,20 @@ should match the line containing `"Rust:"` with a capital R and match the line
|
|||
our failing test, and it will fail to compile because we haven’t yet defined
|
||||
the `search_case_insensitive` function. Feel free to add a skeleton
|
||||
implementation that always returns an empty vector, similar to the way we did
|
||||
for the `search` function in Listing 12-16 to see the test compile and fail.
|
||||
for the `search` function in [Listing 12-16][Listing-12-16] to see the test compile and fail.
|
||||
|
||||
### Implementing the `search_case_insensitive` Function
|
||||
|
||||
The `search_case_insensitive` function, shown in Listing 12-21, will be almost
|
||||
The `search_case_insensitive` function, shown in [Listing 12-21][Listing-12-21], will be almost
|
||||
the same as the `search` function. The only difference is that we’ll lowercase
|
||||
the `query` and each `line` so whatever the case of the input arguments,
|
||||
they’ll be the same case when we check whether the line contains the query.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-12-21]: #Listing-12-21
|
||||
<a name="Listing-12-21"></a>
|
||||
|
||||
```rust
|
||||
pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
let query = query.to_lowercase();
|
||||
|
@ -148,11 +154,14 @@ pub struct Config {
|
|||
Note that we added the `case_sensitive` field that holds a Boolean. Next, we
|
||||
need the `run` function to check the `case_sensitive` field’s value and use
|
||||
that to decide whether to call the `search` function or the
|
||||
`search_case_insensitive` function, as shown in Listing 12-22. Note this still
|
||||
`search_case_insensitive` function, as shown in [Listing 12-22][Listing-12-22]. Note this still
|
||||
won’t compile yet.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-12-22]: #Listing-12-22
|
||||
<a name="Listing-12-22"></a>
|
||||
|
||||
```rust
|
||||
# use std::error::Error;
|
||||
# use std::fs::File;
|
||||
|
@ -200,10 +209,13 @@ working with environment variables are in the `env` module in the standard
|
|||
library, so we want to bring that module into scope with a `use std::env;` line
|
||||
at the top of *src/lib.rs*. Then we’ll use the `var` function from the `env`
|
||||
module to check for an environment variable named `CASE_INSENSITIVE`, as shown
|
||||
in Listing 12-23.
|
||||
in [Listing 12-23][Listing-12-23].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-12-23]: #Listing-12-23
|
||||
<a name="Listing-12-23"></a>
|
||||
|
||||
```rust
|
||||
use std::env;
|
||||
# struct Config {
|
||||
|
@ -250,7 +262,7 @@ of the other methods we’ve seen on `Result`.
|
|||
|
||||
We pass the value in the `case_sensitive` variable to the `Config` instance so
|
||||
the `run` function can read that value and decide whether to call `search` or
|
||||
`search_case_insensitive`, as we implemented in Listing 12-22.
|
||||
`search_case_insensitive`, as we implemented in [Listing 12-22][Listing-12-22].
|
||||
|
||||
Let’s give it a try! First, we’ll run our program without the environment
|
||||
variable set and with the query `to`, which should match any line that contains
|
||||
|
@ -303,3 +315,9 @@ one set to case insensitive.
|
|||
|
||||
The `std::env` module contains many more useful features for dealing with
|
||||
environment variables: check out its documentation to see what is available.
|
||||
|
||||
[Listing-12-20]: ch12-05-working-with-environment-variables.html#Listing-12-20
|
||||
[Listing-12-21]: ch12-05-working-with-environment-variables.html#Listing-12-21
|
||||
[Listing-12-22]: ch12-05-working-with-environment-variables.html#Listing-12-22
|
||||
[Listing-12-23]: ch12-05-working-with-environment-variables.html#Listing-12-23
|
||||
[Listing-12-16]: ch12-04-testing-the-librarys-functionality.html#Listing-12-16
|
||||
|
|
|
@ -47,7 +47,7 @@ data from a successful run ends up in the file. We’ll change that.
|
|||
|
||||
### Printing Errors to Standard Error
|
||||
|
||||
We’ll use the code in Listing 12-24 to change how error messages are printed.
|
||||
We’ll use the code in [Listing 12-24][Listing-12-24] to change how error messages are printed.
|
||||
Because of the refactoring we did earlier in this chapter, all the code that
|
||||
prints error messages is in one function, `main`. The standard library provides
|
||||
the `eprintln!` macro that prints to the standard error stream, so let’s change
|
||||
|
@ -56,6 +56,9 @@ instead.
|
|||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-12-24]: #Listing-12-24
|
||||
<a name="Listing-12-24"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
@ -119,3 +122,5 @@ well tested.
|
|||
|
||||
Next, we’ll explore some Rust features that were influenced by functional
|
||||
languages: closures and iterators.
|
||||
|
||||
[Listing-12-24]: ch12-06-writing-to-stderr-instead-of-stdout.html#Listing-12-24
|
||||
|
|
|
@ -23,12 +23,15 @@ few seconds. We want to call this algorithm only when we need to and only call
|
|||
it once so we don’t make the user wait more than necessary.
|
||||
|
||||
We’ll simulate calling this hypothetical algorithm with the function
|
||||
`simulated_expensive_calculation` shown in Listing 13-1, which will print
|
||||
`simulated_expensive_calculation` shown in [Listing 13-1][Listing-13-1], which will print
|
||||
`calculating slowly...`, wait for two seconds, and then return whatever number
|
||||
we passed in.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-1]: #Listing-13-1
|
||||
<a name="Listing-13-1"></a>
|
||||
|
||||
```rust
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
@ -56,11 +59,14 @@ The required inputs are these:
|
|||
high-intensity workout
|
||||
* A random number that will generate some variety in the workout plans
|
||||
|
||||
The output will be the recommended workout plan. Listing 13-2 shows the `main`
|
||||
The output will be the recommended workout plan. [Listing 13-2][Listing-13-2] shows the `main`
|
||||
function we’ll use.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-2]: #Listing-13-2
|
||||
<a name="Listing-13-2"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let simulated_user_specified_value = 10;
|
||||
|
@ -85,12 +91,15 @@ example in Chapter 2. The `main` function calls a `generate_workout` function
|
|||
with the simulated input values.
|
||||
|
||||
Now that we have the context, let’s get to the algorithm. The function
|
||||
`generate_workout` in Listing 13-3 contains the business logic of the
|
||||
`generate_workout` in [Listing 13-3][Listing-13-3] contains the business logic of the
|
||||
app that we’re most concerned with in this example. The rest of the code
|
||||
changes in this example will be made to this function.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-3]: #Listing-13-3
|
||||
<a name="Listing-13-3"></a>
|
||||
|
||||
```rust
|
||||
# use std::thread;
|
||||
# use std::time::Duration;
|
||||
|
@ -128,7 +137,7 @@ fn generate_workout(intensity: u32, random_number: u32) {
|
|||
plans based on the inputs and calls to the `simulated_expensive_calculation`
|
||||
function</span>
|
||||
|
||||
The code in Listing 13-3 has multiple calls to the slow calculation function.
|
||||
The code in [Listing 13-3][Listing-13-3] has multiple calls to the slow calculation function.
|
||||
The first `if` block calls `simulated_expensive_calculation` twice, the `if`
|
||||
inside the outer `else` doesn’t call it at all, and the code inside the
|
||||
second `else` case calls it once.
|
||||
|
@ -160,10 +169,13 @@ to call it if the result isn’t needed, and we still want to call it only once.
|
|||
|
||||
We could restructure the workout program in many ways. First, we’ll try
|
||||
extracting the duplicated call to the `simulated_expensive_calculation`
|
||||
function into a variable, as shown in Listing 13-4.
|
||||
function into a variable, as shown in [Listing 13-4][Listing-13-4].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-4]: #Listing-13-4
|
||||
<a name="Listing-13-4"></a>
|
||||
|
||||
```rust
|
||||
# use std::thread;
|
||||
# use std::time::Duration;
|
||||
|
@ -217,12 +229,15 @@ code where we actually need the result. This is a use case for closures!
|
|||
|
||||
Instead of always calling the `simulated_expensive_calculation` function before
|
||||
the `if` blocks, we can define a closure and store the *closure* in a variable
|
||||
rather than storing the result of the function call, as shown in Listing 13-5.
|
||||
rather than storing the result of the function call, as shown in [Listing 13-5][Listing-13-5].
|
||||
We can actually move the whole body of `simulated_expensive_calculation` within
|
||||
the closure we’re introducing here.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-5]: #Listing-13-5
|
||||
<a name="Listing-13-5"></a>
|
||||
|
||||
```rust
|
||||
# use std::thread;
|
||||
# use std::time::Duration;
|
||||
|
@ -262,10 +277,13 @@ With the closure defined, we can change the code in the `if` blocks to call the
|
|||
closure to execute the code and get the resulting value. We call a closure like
|
||||
we do a function: we specify the variable name that holds the closure
|
||||
definition and follow it with parentheses containing the argument values we
|
||||
want to use, as shown in Listing 13-6.
|
||||
want to use, as shown in [Listing 13-6][Listing-13-6].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-6]: #Listing-13-6
|
||||
<a name="Listing-13-6"></a>
|
||||
|
||||
```rust
|
||||
# use std::thread;
|
||||
# use std::time::Duration;
|
||||
|
@ -305,7 +323,7 @@ defined</span>
|
|||
Now the expensive calculation is called in only one place, and we’re only
|
||||
executing that code where we need the results.
|
||||
|
||||
However, we’ve reintroduced one of the problems from Listing 13-3: we’re still
|
||||
However, we’ve reintroduced one of the problems from [Listing 13-3][Listing-13-3]: we’re still
|
||||
calling the closure twice in the first `if` block, which will call the
|
||||
expensive code twice and make the user wait twice as long as they need to. We
|
||||
could fix this problem by creating a variable local to that `if` block to hold
|
||||
|
@ -335,11 +353,14 @@ available.
|
|||
|
||||
As with variables, we can add type annotations if we want to increase
|
||||
explicitness and clarity at the cost of being more verbose than is strictly
|
||||
necessary. Annotating the types for the closure we defined in Listing 13-5
|
||||
would look like the definition shown in Listing 13-7.
|
||||
necessary. Annotating the types for the closure we defined in [Listing 13-5][Listing-13-5]
|
||||
would look like the definition shown in [Listing 13-7][Listing-13-7].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-7]: #Listing-13-7
|
||||
<a name="Listing-13-7"></a>
|
||||
|
||||
```rust
|
||||
# use std::thread;
|
||||
# use std::time::Duration;
|
||||
|
@ -375,7 +396,7 @@ optional because the closure body has only one expression. These are all valid
|
|||
definitions that will produce the same behavior when they’re called.
|
||||
|
||||
Closure definitions will have one concrete type inferred for each of their
|
||||
parameters and for their return value. For instance, Listing 13-8 shows the
|
||||
parameters and for their return value. For instance, [Listing 13-8][Listing-13-8] shows the
|
||||
definition of a short closure that just returns the value it receives as a
|
||||
parameter. This closure isn’t very useful except for the purposes of this
|
||||
example. Note that we haven’t added any type annotations to the definition: if
|
||||
|
@ -384,6 +405,9 @@ first time and a `u32` the second time, we’ll get an error.
|
|||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-8]: #Listing-13-8
|
||||
<a name="Listing-13-8"></a>
|
||||
|
||||
```rust,ignore
|
||||
let example_closure = |x| x;
|
||||
|
||||
|
@ -415,7 +439,7 @@ error if we try to use a different type with the same closure.
|
|||
|
||||
### Storing Closures Using Generic Parameters and the `Fn` Traits
|
||||
|
||||
Let’s return to our workout generation app. In Listing 13-6, our code was still
|
||||
Let’s return to our workout generation app. In [Listing 13-6][Listing-13-6], our code was still
|
||||
calling the expensive calculation closure more times than it needed to. One
|
||||
option to solve this issue is to save the result of the expensive closure in a
|
||||
variable for reuse and use the variable in each place we need the result,
|
||||
|
@ -446,11 +470,14 @@ and return values the closures must have to match this trait bound. In this
|
|||
case, our closure has a parameter of type `u32` and returns a `u32`, so the
|
||||
trait bound we specify is `Fn(u32) -> u32`.
|
||||
|
||||
Listing 13-9 shows the definition of the `Cacher` struct that holds a closure
|
||||
[Listing 13-9][Listing-13-9] shows the definition of the `Cacher` struct that holds a closure
|
||||
and an optional result value.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-9]: #Listing-13-9
|
||||
<a name="Listing-13-9"></a>
|
||||
|
||||
```rust
|
||||
struct Cacher<T>
|
||||
where T: Fn(u32) -> u32
|
||||
|
@ -481,11 +508,13 @@ result within a `Some` variant in the `value` field. Then if the code asks for
|
|||
the result of the closure again, instead of executing the closure again, the
|
||||
`Cacher` will return the result held in the `Some` variant.
|
||||
|
||||
The logic around the `value` field we’ve just described is defined in Listing
|
||||
13-10.
|
||||
The logic around the `value` field we’ve just described is defined in [Listing 13-10][Listing-13-10].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-10]: #Listing-13-10
|
||||
<a name="Listing-13-10"></a>
|
||||
|
||||
```rust
|
||||
# struct Cacher<T>
|
||||
# where T: Fn(u32) -> u32
|
||||
|
@ -539,11 +568,14 @@ If `self.value` is `None`, the code calls the closure stored in
|
|||
`self.calculation`, saves the result in `self.value` for future use, and
|
||||
returns the value as well.
|
||||
|
||||
Listing 13-11 shows how we can use this `Cacher` struct in the function
|
||||
`generate_workout` from Listing 13-6.
|
||||
[Listing 13-11][Listing-13-11] shows how we can use this `Cacher` struct in the function
|
||||
`generate_workout` from [Listing 13-6][Listing-13-6].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-11]: #Listing-13-11
|
||||
<a name="Listing-13-11"></a>
|
||||
|
||||
```rust
|
||||
# use std::thread;
|
||||
# use std::time::Duration;
|
||||
|
@ -615,7 +647,7 @@ call the `value` method on the `Cacher` instance. We can call the `value`
|
|||
method as many times as we want, or not call it at all, and the expensive
|
||||
calculation will be run a maximum of once.
|
||||
|
||||
Try running this program with the `main` function from Listing 13-2. Change the
|
||||
Try running this program with the `main` function from [Listing 13-2][Listing-13-2]. Change the
|
||||
values in the `simulated_user_specified_value` and `simulated_random_number`
|
||||
variables to verify that in all the cases in the various `if` and `else`
|
||||
blocks, `calculating slowly...` appears only once and only when needed. The
|
||||
|
@ -651,8 +683,8 @@ passed into it. We call the `value` method on this `Cacher` instance with an
|
|||
`arg` value of 1 and then an `arg` value of 2, and we expect the call to
|
||||
`value` with the `arg` value of 2 to return 2.
|
||||
|
||||
Run this test with the `Cacher` implementation in Listing 13-9 and Listing
|
||||
13-10, and the test will fail on the `assert_eq!` with this message:
|
||||
Run this test with the `Cacher` implementation in [Listing 13-9][Listing-13-9] and [Listing 13-10][Listing-13-10],
|
||||
and the test will fail on the `assert_eq!` with this message:
|
||||
|
||||
```text
|
||||
thread 'call_with_different_values' panicked at 'assertion failed: `(left == right)`
|
||||
|
@ -685,11 +717,14 @@ functions. However, closures have an additional capability that functions don’
|
|||
have: they can capture their environment and access variables from the scope in
|
||||
which they’re defined.
|
||||
|
||||
Listing 13-12 has an example of a closure stored in the `equal_to_x` variable
|
||||
[Listing 13-12][Listing-13-12] has an example of a closure stored in the `equal_to_x` variable
|
||||
that uses the `x` variable from the closure’s surrounding environment.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-12]: #Listing-13-12
|
||||
<a name="Listing-13-12"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = 4;
|
||||
|
@ -763,7 +798,7 @@ When you create a closure, Rust infers which trait to use based on how the
|
|||
closure uses the values from the environment. All closures implement `FnOnce`
|
||||
because they can all be called at least once. Closures that don’t move the
|
||||
captured variables also implement `FnMut`, and closures that don’t need mutable
|
||||
access to the captured variables also implement `Fn`. In Listing 13-12, the
|
||||
access to the captured variables also implement `Fn`. In [Listing 13-12][Listing-13-12], the
|
||||
`equal_to_x` closure borrows `x` immutably (so `equal_to_x` has the `Fn` trait)
|
||||
because the body of the closure only needs to read the value in `x`.
|
||||
|
||||
|
@ -773,7 +808,7 @@ technique is mostly useful when passing a closure to a new thread to move the
|
|||
data so it’s owned by the new thread.
|
||||
|
||||
We’ll have more examples of `move` closures in Chapter 16 when we talk about
|
||||
concurrency. For now, here’s the code from Listing 13-12 with the `move`
|
||||
concurrency. For now, here’s the code from [Listing 13-12][Listing-13-12] with the `move`
|
||||
keyword added to the closure definition and using vectors instead of integers,
|
||||
because integers can be copied rather than moved; note that this code will not
|
||||
yet compile.
|
||||
|
@ -821,3 +856,16 @@ on what happens in the closure body.
|
|||
|
||||
To illustrate situations where closures that can capture their environment are
|
||||
useful as function parameters, let’s move on to our next topic: iterators.
|
||||
|
||||
[Listing-13-1]: ch13-01-closures.html#Listing-13-1
|
||||
[Listing-13-2]: ch13-01-closures.html#Listing-13-2
|
||||
[Listing-13-3]: ch13-01-closures.html#Listing-13-3
|
||||
[Listing-13-4]: ch13-01-closures.html#Listing-13-4
|
||||
[Listing-13-5]: ch13-01-closures.html#Listing-13-5
|
||||
[Listing-13-6]: ch13-01-closures.html#Listing-13-6
|
||||
[Listing-13-7]: ch13-01-closures.html#Listing-13-7
|
||||
[Listing-13-8]: ch13-01-closures.html#Listing-13-8
|
||||
[Listing-13-9]: ch13-01-closures.html#Listing-13-9
|
||||
[Listing-13-10]: ch13-01-closures.html#Listing-13-10
|
||||
[Listing-13-11]: ch13-01-closures.html#Listing-13-11
|
||||
[Listing-13-12]: ch13-01-closures.html#Listing-13-12
|
||||
|
|
|
@ -7,10 +7,13 @@ have to reimplement that logic yourself.
|
|||
|
||||
In Rust, iterators are *lazy*, meaning they have no effect until you call
|
||||
methods that consume the iterator to use it up. For example, the code in
|
||||
Listing 13-13 creates an iterator over the items in the vector `v1` by calling
|
||||
[Listing 13-13][Listing-13-13] creates an iterator over the items in the vector `v1` by calling
|
||||
the `iter` method defined on `Vec<T>`. This code by itself doesn’t do anything
|
||||
useful.
|
||||
|
||||
[Listing-13-13]: #Listing-13-13
|
||||
<a name="Listing-13-13"></a>
|
||||
|
||||
```rust
|
||||
let v1 = vec![1, 2, 3];
|
||||
|
||||
|
@ -19,16 +22,19 @@ let v1_iter = v1.iter();
|
|||
|
||||
<span class="caption">Listing 13-13: Creating an iterator</span>
|
||||
|
||||
Once we’ve created an iterator, we can use it in a variety of ways. In Listing
|
||||
3-5 in Chapter 3, we used iterators with `for` loops to execute some code on
|
||||
Once we’ve created an iterator, we can use it in a variety of ways. In [Listing 3-5][Listing-3-5]
|
||||
in Chapter 3, we used iterators with `for` loops to execute some code on
|
||||
each item, although we glossed over what the call to `iter` did until now.
|
||||
|
||||
The example in Listing 13-14 separates the creation of the iterator from the
|
||||
The example in [Listing 13-14][Listing-13-14] separates the creation of the iterator from the
|
||||
use of the iterator in the `for` loop. The iterator is stored in the `v1_iter`
|
||||
variable, and no iteration takes place at that time. When the `for` loop is
|
||||
called using the iterator in `v1_iter`, each element in the iterator is used in
|
||||
one iteration of the loop, which prints out each value.
|
||||
|
||||
[Listing-13-14]: #Listing-13-14
|
||||
<a name="Listing-13-14"></a>
|
||||
|
||||
```rust
|
||||
let v1 = vec![1, 2, 3];
|
||||
|
||||
|
@ -79,12 +85,15 @@ The `Iterator` trait only requires implementors to define one method: the
|
|||
`next` method, which returns one item of the iterator at a time wrapped in
|
||||
`Some` and, when iteration is over, returns `None`.
|
||||
|
||||
We can call the `next` method on iterators directly; Listing 13-15 demonstrates
|
||||
We can call the `next` method on iterators directly; [Listing 13-15][Listing-13-15] demonstrates
|
||||
what values are returned from repeated calls to `next` on the iterator created
|
||||
from the vector.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-13-15]: #Listing-13-15
|
||||
<a name="Listing-13-15"></a>
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn iterator_demonstration() {
|
||||
|
@ -129,11 +138,14 @@ Methods that call `next` are called *consuming adaptors*, because calling them
|
|||
uses up the iterator. One example is the `sum` method, which takes ownership of
|
||||
the iterator and iterates through the items by repeatedly calling `next`, thus
|
||||
consuming the iterator. As it iterates through, it adds each item to a running
|
||||
total and returns the total when iteration is complete. Listing 13-16 has a
|
||||
total and returns the total when iteration is complete. [Listing 13-16][Listing-13-16] has a
|
||||
test illustrating a use of the `sum` method:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-13-16]: #Listing-13-16
|
||||
<a name="Listing-13-16"></a>
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn iterator_sum() {
|
||||
|
@ -161,13 +173,16 @@ multiple calls to iterator adaptors to perform complex actions in a readable
|
|||
way. But because all iterators are lazy, you have to call one of the consuming
|
||||
adaptor methods to get results from calls to iterator adaptors.
|
||||
|
||||
Listing 13-17 shows an example of calling the iterator adaptor method `map`,
|
||||
[Listing 13-17][Listing-13-17] shows an example of calling the iterator adaptor method `map`,
|
||||
which takes a closure to call on each item to produce a new iterator. The
|
||||
closure here creates a new iterator in which each item from the vector has been
|
||||
incremented by 1. However, this code produces a warning:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-17]: #Listing-13-17
|
||||
<a name="Listing-13-17"></a>
|
||||
|
||||
```rust
|
||||
let v1: Vec<i32> = vec![1, 2, 3];
|
||||
|
||||
|
@ -190,20 +205,23 @@ and do nothing unless consumed
|
|||
= note: #[warn(unused_must_use)] on by default
|
||||
```
|
||||
|
||||
The code in Listing 13-17 doesn’t do anything; the closure we’ve specified
|
||||
The code in [Listing 13-17][Listing-13-17] doesn’t do anything; the closure we’ve specified
|
||||
never gets called. The warning reminds us why: iterator adaptors are lazy, and
|
||||
we need to consume the iterator here.
|
||||
|
||||
To fix this and consume the iterator, we’ll use the `collect` method, which we
|
||||
used in Chapter 12 with `env::args` in Listing 12-1. This method consumes the
|
||||
used in Chapter 12 with `env::args` in [Listing 12-1][Listing-12-1]. This method consumes the
|
||||
iterator and collects the resulting values into a collection data type.
|
||||
|
||||
In Listing 13-18, we collect the results of iterating over the iterator that’s
|
||||
In [Listing 13-18][Listing-13-18], we collect the results of iterating over the iterator that’s
|
||||
returned from the call to `map` into a vector. This vector will end up
|
||||
containing each item from the original vector incremented by 1.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-18]: #Listing-13-18
|
||||
<a name="Listing-13-18"></a>
|
||||
|
||||
```rust
|
||||
let v1: Vec<i32> = vec![1, 2, 3];
|
||||
|
||||
|
@ -230,12 +248,15 @@ the iterator and returns a Boolean. If the closure returns `true`, the value
|
|||
will be included in the iterator produced by `filter`. If the closure returns
|
||||
`false`, the value won’t be included in the resulting iterator.
|
||||
|
||||
In Listing 13-19, we use `filter` with a closure that captures the `shoe_size`
|
||||
In [Listing 13-19][Listing-13-19], we use `filter` with a closure that captures the `shoe_size`
|
||||
variable from its environment to iterate over a collection of `Shoe` struct
|
||||
instances. It will return only shoes that are the specified size.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-13-19]: #Listing-13-19
|
||||
<a name="Listing-13-19"></a>
|
||||
|
||||
```rust
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct Shoe {
|
||||
|
@ -305,11 +326,14 @@ First, we’ll create a struct to hold some values. Then we’ll make this struc
|
|||
into an iterator by implementing the `Iterator` trait and using the values in
|
||||
that implementation.
|
||||
|
||||
Listing 13-20 has the definition of the `Counter` struct and an associated
|
||||
[Listing 13-20][Listing-13-20] has the definition of the `Counter` struct and an associated
|
||||
`new` function to create instances of `Counter`:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-13-20]: #Listing-13-20
|
||||
<a name="Listing-13-20"></a>
|
||||
|
||||
```rust
|
||||
struct Counter {
|
||||
count: u32,
|
||||
|
@ -334,10 +358,13 @@ always starting new instances with a value of 0 in the `count` field.
|
|||
|
||||
Next, we’ll implement the `Iterator` trait for our `Counter` type by defining
|
||||
the body of the `next` method to specify what we want to happen when this
|
||||
iterator is used, as shown in Listing 13-21:
|
||||
iterator is used, as shown in [Listing 13-21][Listing-13-21]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-13-21]: #Listing-13-21
|
||||
<a name="Listing-13-21"></a>
|
||||
|
||||
```rust
|
||||
# struct Counter {
|
||||
# count: u32,
|
||||
|
@ -372,13 +399,16 @@ our iterator will return `None`.
|
|||
|
||||
#### Using Our `Counter` Iterator’s `next` Method
|
||||
|
||||
Once we’ve implemented the `Iterator` trait, we have an iterator! Listing 13-22
|
||||
Once we’ve implemented the `Iterator` trait, we have an iterator! [Listing 13-22][Listing-13-22]
|
||||
shows a test demonstrating that we can use the iterator functionality of our
|
||||
`Counter` struct by calling the `next` method on it directly, just as we did
|
||||
with the iterator created from a vector in Listing 13-15.
|
||||
with the iterator created from a vector in [Listing 13-15][Listing-13-15].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-13-22]: #Listing-13-22
|
||||
<a name="Listing-13-22"></a>
|
||||
|
||||
```rust
|
||||
# struct Counter {
|
||||
# count: u32,
|
||||
|
@ -428,10 +458,13 @@ For example, if for some reason we wanted to take the values produced by an
|
|||
instance of `Counter`, pair them with values produced by another `Counter`
|
||||
instance after skipping the first value, multiply each pair together, keep only
|
||||
those results that are divisible by 3, and add all the resulting values
|
||||
together, we could do so, as shown in the test in Listing 13-23:
|
||||
together, we could do so, as shown in the test in [Listing 13-23][Listing-13-23]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-13-23]: #Listing-13-23
|
||||
<a name="Listing-13-23"></a>
|
||||
|
||||
```rust
|
||||
# struct Counter {
|
||||
# count: u32,
|
||||
|
@ -480,3 +513,17 @@ iterators return `None`.
|
|||
All of these method calls are possible because we specified how the `next`
|
||||
method works, and the standard library provides default implementations for
|
||||
other methods that call `next`.
|
||||
|
||||
[Listing-12-1]: ch12-01-accepting-command-line-arguments.html#Listing-12-1
|
||||
[Listing-13-13]: ch13-02-iterators.html#Listing-13-13
|
||||
[Listing-13-14]: ch13-02-iterators.html#Listing-13-14
|
||||
[Listing-13-15]: ch13-02-iterators.html#Listing-13-15
|
||||
[Listing-13-16]: ch13-02-iterators.html#Listing-13-16
|
||||
[Listing-13-17]: ch13-02-iterators.html#Listing-13-17
|
||||
[Listing-13-18]: ch13-02-iterators.html#Listing-13-18
|
||||
[Listing-13-19]: ch13-02-iterators.html#Listing-13-19
|
||||
[Listing-13-20]: ch13-02-iterators.html#Listing-13-20
|
||||
[Listing-13-21]: ch13-02-iterators.html#Listing-13-21
|
||||
[Listing-13-22]: ch13-02-iterators.html#Listing-13-22
|
||||
[Listing-13-23]: ch13-02-iterators.html#Listing-13-23
|
||||
[Listing-3-5]: ch03-05-control-flow.html#Listing-3-5
|
||||
|
|
|
@ -8,14 +8,17 @@ concise. Let’s look at how iterators can improve our implementation of the
|
|||
|
||||
### Removing a `clone` Using an Iterator
|
||||
|
||||
In Listing 12-6, we added code that took a slice of `String` values and created
|
||||
In [Listing 12-6][Listing-12-6], we added code that took a slice of `String` values and created
|
||||
an instance of the `Config` struct by indexing into the slice and cloning the
|
||||
values, allowing the `Config` struct to own those values. In Listing 13-24,
|
||||
values, allowing the `Config` struct to own those values. In [Listing 13-24][Listing-13-24],
|
||||
we’ve reproduced the implementation of the `Config::new` function as it was in
|
||||
Listing 12-23:
|
||||
[Listing 12-23][Listing-12-23]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-13-24]: #Listing-13-24
|
||||
<a name="Listing-13-24"></a>
|
||||
|
||||
```rust,ignore
|
||||
impl Config {
|
||||
pub fn new(args: &[String]) -> Result<Config, &'static str> {
|
||||
|
@ -34,7 +37,7 @@ impl Config {
|
|||
```
|
||||
|
||||
<span class="caption">Listing 13-24: Reproduction of the `Config::new` function
|
||||
from Listing 12-23</span>
|
||||
from [Listing 12-23][Listing-12-23]</span>
|
||||
|
||||
At the time, we said not to worry about the inefficient `clone` calls because
|
||||
we would remove them in the future. Well, that time is now!
|
||||
|
@ -73,12 +76,15 @@ fn main() {
|
|||
}
|
||||
```
|
||||
|
||||
We’ll change the start of the `main` function that we had in Listing 12-24 at
|
||||
to the code in Listing 13-25. This won’t compile until we update `Config::new`
|
||||
We’ll change the start of the `main` function that we had in [Listing 12-24][Listing-12-24] at
|
||||
to the code in [Listing 13-25][Listing-13-25]. This won’t compile until we update `Config::new`
|
||||
as well.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-13-25]: #Listing-13-25
|
||||
<a name="Listing-13-25"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let config = Config::new(env::args()).unwrap_or_else(|err| {
|
||||
|
@ -100,11 +106,14 @@ we’re passing ownership of the iterator returned from `env::args` to
|
|||
|
||||
Next, we need to update the definition of `Config::new`. In your I/O project’s
|
||||
*src/lib.rs* file, let’s change the signature of `Config::new` to look like
|
||||
Listing 13-26. This still won’t compile because we need to update the function
|
||||
[Listing 13-26][Listing-13-26]. This still won’t compile because we need to update the function
|
||||
body.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-13-26]: #Listing-13-26
|
||||
<a name="Listing-13-26"></a>
|
||||
|
||||
```rust,ignore
|
||||
impl Config {
|
||||
pub fn new(mut args: std::env::Args) -> Result<Config, &'static str> {
|
||||
|
@ -125,11 +134,14 @@ keyword into the specification of the `args` parameter to make it mutable.
|
|||
|
||||
Next, we’ll fix the body of `Config::new`. The standard library documentation
|
||||
also mentions that `std::env::Args` implements the `Iterator` trait, so we know
|
||||
we can call the `next` method on it! Listing 13-27 updates the code from
|
||||
Listing 12-23 to use the `next` method:
|
||||
we can call the `next` method on it! [Listing 13-27][Listing-13-27] updates the code from
|
||||
[Listing 12-23][Listing-12-23] to use the `next` method:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-13-27]: #Listing-13-27
|
||||
<a name="Listing-13-27"></a>
|
||||
|
||||
```rust
|
||||
# fn main() {}
|
||||
# use std::env;
|
||||
|
@ -175,10 +187,13 @@ the same thing for the `filename` value.
|
|||
### Making Code Clearer with Iterator Adaptors
|
||||
|
||||
We can also take advantage of iterators in the `search` function in our I/O
|
||||
project, which is reproduced here in Listing 13-28 as it was in Listing 12-19:
|
||||
project, which is reproduced here in [Listing 13-28][Listing-13-28] as it was in [Listing 12-19][Listing-12-19]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-13-28]: #Listing-13-28
|
||||
<a name="Listing-13-28"></a>
|
||||
|
||||
```rust,ignore
|
||||
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
let mut results = Vec::new();
|
||||
|
@ -194,17 +209,20 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
|||
```
|
||||
|
||||
<span class="caption">Listing 13-28: The implementation of the `search`
|
||||
function from Listing 12-19</span>
|
||||
function from [Listing 12-19][Listing-12-19]</span>
|
||||
|
||||
We can write this code in a more concise way using iterator adaptor methods.
|
||||
Doing so also lets us avoid having a mutable intermediate `results` vector. The
|
||||
functional programming style prefers to minimize the amount of mutable state to
|
||||
make code clearer. Removing the mutable state might enable a future enhancement
|
||||
to make searching happen in parallel, because we wouldn’t have to manage
|
||||
concurrent access to the `results` vector. Listing 13-29 shows this change:
|
||||
concurrent access to the `results` vector. [Listing 13-29][Listing-13-29] shows this change:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-13-29]: #Listing-13-29
|
||||
<a name="Listing-13-29"></a>
|
||||
|
||||
```rust,ignore
|
||||
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
||||
contents.lines()
|
||||
|
@ -217,16 +235,16 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
|
|||
implementation of the `search` function</span>
|
||||
|
||||
Recall that the purpose of the `search` function is to return all lines in
|
||||
`contents` that contain the `query`. Similar to the `filter` example in Listing
|
||||
13-19, this code uses the `filter` adaptor to keep only the lines that
|
||||
`contents` that contain the `query`. Similar to the `filter` example in [Listing 13-19][Listing-13-19],
|
||||
this code uses the `filter` adaptor to keep only the lines that
|
||||
`line.contains(query)` returns `true` for. We then collect the matching lines
|
||||
into another vector with `collect`. Much simpler! Feel free to make the same
|
||||
change to use iterator methods in the `search_case_insensitive` function as
|
||||
well.
|
||||
|
||||
The next logical question is which style you should choose in your own code and
|
||||
why: the original implementation in Listing 13-28 or the version using
|
||||
iterators in Listing 13-29. Most Rust programmers prefer to use the iterator
|
||||
why: the original implementation in [Listing 13-28][Listing-13-28] or the version using
|
||||
iterators in [Listing 13-29][Listing-13-29]. Most Rust programmers prefer to use the iterator
|
||||
style. It’s a bit tougher to get the hang of at first, but once you get a feel
|
||||
for the various iterator adaptors and what they do, iterators can be easier to
|
||||
understand. Instead of fiddling with the various bits of looping and building
|
||||
|
@ -238,3 +256,15 @@ the iterator must pass.
|
|||
But are the two implementations truly equivalent? The intuitive assumption
|
||||
might be that the more low-level loop will be faster. Let’s talk about
|
||||
performance.
|
||||
|
||||
[Listing-13-19]: ch13-02-iterators.html#Listing-13-19
|
||||
[Listing-12-24]: ch12-06-writing-to-stderr-instead-of-stdout.html#Listing-12-24
|
||||
[Listing-12-6]: ch12-03-improving-error-handling-and-modularity.html#Listing-12-6
|
||||
[Listing-12-23]: ch12-05-working-with-environment-variables.html#Listing-12-23
|
||||
[Listing-13-24]: ch13-03-improving-our-io-project.html#Listing-13-24
|
||||
[Listing-13-25]: ch13-03-improving-our-io-project.html#Listing-13-25
|
||||
[Listing-13-26]: ch13-03-improving-our-io-project.html#Listing-13-26
|
||||
[Listing-13-27]: ch13-03-improving-our-io-project.html#Listing-13-27
|
||||
[Listing-13-28]: ch13-03-improving-our-io-project.html#Listing-13-28
|
||||
[Listing-13-29]: ch13-03-improving-our-io-project.html#Listing-13-29
|
||||
[Listing-12-19]: ch12-04-testing-the-librarys-functionality.html#Listing-12-19
|
||||
|
|
|
@ -23,7 +23,7 @@ your crate is *implemented*.
|
|||
|
||||
Documentation comments use three slashes, `///`, instead of two and support
|
||||
Markdown notation for formatting the text. Place documentation comments just
|
||||
before the item they’re documenting. Listing 14-1 shows documentation comments
|
||||
before the item they’re documenting. [Listing 14-1][Listing-14-1] shows documentation comments
|
||||
for an `add_one` function in a crate named `my_crate`:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
@ -37,6 +37,9 @@ for an `add_one` function in a crate named `my_crate`:
|
|||
/// let five = 5;
|
||||
///
|
||||
/// assert_eq!(6, my_crate::add_one(5));
|
||||
[Listing-14-1]: #Listing-14-1
|
||||
<a name="Listing-14-1"></a>
|
||||
|
||||
/// ```
|
||||
pub fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
|
@ -57,7 +60,10 @@ For convenience, running `cargo doc --open` will build the HTML for your
|
|||
current crate’s documentation (as well as the documentation for all of your
|
||||
crate’s dependencies) and open the result in a web browser. Navigate to the
|
||||
`add_one` function and you’ll see how the text in the documentation comments is
|
||||
rendered, as shown in Figure 14-1:
|
||||
rendered, as shown in [Figure 14-1][Figure-14-1]:
|
||||
|
||||
[Figure-14-1]: #Figure-14-1
|
||||
<a name="Figure-14-1"></a>
|
||||
|
||||
<img alt="Rendered HTML documentation for the `add_one` function of `my_crate`" src="img/trpl14-01.png" class="center" />
|
||||
|
||||
|
@ -66,7 +72,7 @@ function</span>
|
|||
|
||||
#### Commonly Used Sections
|
||||
|
||||
We used the `# Examples` Markdown heading in Listing 14-1 to create a section
|
||||
We used the `# Examples` Markdown heading in [Listing 14-1][Listing-14-1] to create a section
|
||||
in the HTML with the title “Examples.” Here are some other sections that crate
|
||||
authors commonly use in their documentation:
|
||||
|
||||
|
@ -93,7 +99,7 @@ test` will run the code examples in your documentation as tests! Nothing is
|
|||
better than documentation with examples. But nothing is worse than examples
|
||||
that don’t work because the code has changed since the documentation was
|
||||
written. If we run `cargo test` with the documentation for the `add_one`
|
||||
function from Listing 14-1, we will see a section in the test results like this:
|
||||
function from [Listing 14-1][Listing-14-1], we will see a section in the test results like this:
|
||||
|
||||
```text
|
||||
Doc-tests my_crate
|
||||
|
@ -119,10 +125,13 @@ module as a whole.
|
|||
For example, if we want to add documentation that describes the purpose of the
|
||||
`my_crate` crate that contains the `add_one` function, we can add documentation
|
||||
comments that start with `//!` to the beginning of the *src/lib.rs* file, as
|
||||
shown in Listing 14-2:
|
||||
shown in [Listing 14-2][Listing-14-2]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-14-2]: #Listing-14-2
|
||||
<a name="Listing-14-2"></a>
|
||||
|
||||
```rust,ignore
|
||||
//! # My Crate
|
||||
//!
|
||||
|
@ -144,7 +153,10 @@ is the crate root. These comments describe the entire crate.
|
|||
|
||||
When we run `cargo doc --open`, these comments will display on the front
|
||||
page of the documentation for `my_crate` above the list of public items in the
|
||||
crate, as shown in Figure 14-2:
|
||||
crate, as shown in [Figure 14-2][Figure-14-2]:
|
||||
|
||||
[Figure-14-2]: #Figure-14-2
|
||||
<a name="Figure-14-2"></a>
|
||||
|
||||
<img alt="Rendered HTML documentation with a comment for the crate as a whole" src="img/trpl14-02.png" class="center" />
|
||||
|
||||
|
@ -183,10 +195,13 @@ defined in the other location instead.
|
|||
For example, say we made a library named `art` for modeling artistic concepts.
|
||||
Within this library are two modules: a `kinds` module containing two enums
|
||||
named `PrimaryColor` and `SecondaryColor` and a `utils` module containing a
|
||||
function named `mix`, as shown in Listing 14-3:
|
||||
function named `mix`, as shown in [Listing 14-3][Listing-14-3]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-14-3]: #Listing-14-3
|
||||
<a name="Listing-14-3"></a>
|
||||
|
||||
```rust,ignore
|
||||
//! # Art
|
||||
//!
|
||||
|
@ -222,9 +237,12 @@ pub mod utils {
|
|||
<span class="caption">Listing 14-3: An `art` library with items organized into
|
||||
`kinds` and `utils` modules</span>
|
||||
|
||||
Figure 14-3 shows what the front page of the documentation for this crate
|
||||
[Figure 14-3][Figure-14-3] shows what the front page of the documentation for this crate
|
||||
generated by `cargo doc` would look like:
|
||||
|
||||
[Figure-14-3]: #Figure-14-3
|
||||
<a name="Figure-14-3"></a>
|
||||
|
||||
<img alt="Rendered documentation for the `art` crate that lists the `kinds` and `utils` modules" src="img/trpl14-03.png" class="center" />
|
||||
|
||||
<span class="caption">Figure 14-3: Front page of the documentation for `art`
|
||||
|
@ -236,11 +254,14 @@ see them.
|
|||
|
||||
Another crate that depends on this library would need `use` statements that
|
||||
import the items from `art`, specifying the module structure that’s currently
|
||||
defined. Listing 14-4 shows an example of a crate that uses the `PrimaryColor`
|
||||
defined. [Listing 14-4][Listing-14-4] shows an example of a crate that uses the `PrimaryColor`
|
||||
and `mix` items from the `art` crate:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-14-4]: #Listing-14-4
|
||||
<a name="Listing-14-4"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate art;
|
||||
|
||||
|
@ -257,7 +278,7 @@ fn main() {
|
|||
<span class="caption">Listing 14-4: A crate using the `art` crate’s items with
|
||||
its internal structure exported</span>
|
||||
|
||||
The author of the code in Listing 14-4, which uses the `art` crate, had to
|
||||
The author of the code in [Listing 14-4][Listing-14-4], which uses the `art` crate, had to
|
||||
figure out that `PrimaryColor` is in the `kinds` module and `mix` is in the
|
||||
`utils` module. The module structure of the `art` crate is more relevant to
|
||||
developers working on the `art` crate than to developers using the `art` crate.
|
||||
|
@ -269,11 +290,14 @@ where to look, and the structure is inconvenient because developers must
|
|||
specify the module names in the `use` statements.
|
||||
|
||||
To remove the internal organization from the public API, we can modify the
|
||||
`art` crate code in Listing 14-3 to add `pub use` statements to re-export the
|
||||
items at the top level, as shown in Listing 14-5:
|
||||
`art` crate code in [Listing 14-3][Listing-14-3] to add `pub use` statements to re-export the
|
||||
items at the top level, as shown in [Listing 14-5][Listing-14-5]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-14-5]: #Listing-14-5
|
||||
<a name="Listing-14-5"></a>
|
||||
|
||||
```rust,ignore
|
||||
//! # Art
|
||||
//!
|
||||
|
@ -296,20 +320,26 @@ pub mod utils {
|
|||
items</span>
|
||||
|
||||
The API documentation that `cargo doc` generates for this crate will now list
|
||||
and link re-exports on the front page, as shown in Figure 14-4, making the
|
||||
and link re-exports on the front page, as shown in [Figure 14-4][Figure-14-4], making the
|
||||
`PrimaryColor` and `SecondaryColor` types and the `mix` function easier to find.
|
||||
|
||||
[Figure-14-4]: #Figure-14-4
|
||||
<a name="Figure-14-4"></a>
|
||||
|
||||
<img alt="Rendered documentation for the `art` crate with the re-exports on the front page" src="img/trpl14-04.png" class="center" />
|
||||
|
||||
<span class="caption">Figure 14-4: The front page of the documentation for `art`
|
||||
that lists the re-exports</span>
|
||||
|
||||
The `art` crate users can still see and use the internal structure from Listing
|
||||
14-3 as demonstrated in Listing 14-4, or they can use the more convenient
|
||||
structure in Listing 14-5, as shown in Listing 14-6:
|
||||
The `art` crate users can still see and use the internal structure from [Listing 14-3][Listing-14-3]
|
||||
as demonstrated in [Listing 14-4][Listing-14-4], or they can use the more convenient
|
||||
structure in [Listing 14-5][Listing-14-5], as shown in [Listing 14-6][Listing-14-6]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-14-6]: #Listing-14-6
|
||||
<a name="Listing-14-6"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate art;
|
||||
|
||||
|
@ -514,3 +544,14 @@ $ cargo yank --vers 1.0.1 --undo
|
|||
A yank *does not* delete any code. For example, the yank feature is not
|
||||
intended for deleting accidentally uploaded secrets. If that happens, you must
|
||||
reset those secrets immediately.
|
||||
|
||||
[Listing-14-1]: ch14-02-publishing-to-crates-io.html#Listing-14-1
|
||||
[Figure-14-1]: ch14-02-publishing-to-crates-io.html#Figure-14-1
|
||||
[Listing-14-2]: ch14-02-publishing-to-crates-io.html#Listing-14-2
|
||||
[Figure-14-2]: ch14-02-publishing-to-crates-io.html#Figure-14-2
|
||||
[Listing-14-3]: ch14-02-publishing-to-crates-io.html#Listing-14-3
|
||||
[Figure-14-3]: ch14-02-publishing-to-crates-io.html#Figure-14-3
|
||||
[Listing-14-4]: ch14-02-publishing-to-crates-io.html#Listing-14-4
|
||||
[Listing-14-5]: ch14-02-publishing-to-crates-io.html#Listing-14-5
|
||||
[Figure-14-4]: ch14-02-publishing-to-crates-io.html#Figure-14-4
|
||||
[Listing-14-6]: ch14-02-publishing-to-crates-io.html#Listing-14-6
|
||||
|
|
|
@ -140,10 +140,13 @@ we need to be explicit about the dependency relationships between the crates.
|
|||
Next, let’s use the `add_one` function from the `add-one` crate in the `adder`
|
||||
crate. Open the *adder/src/main.rs* file and add an `extern crate` line at
|
||||
the top to bring the new `add-one` library crate into scope. Then change the
|
||||
`main` function to call the `add_one` function, as in Listing 14-7:
|
||||
`main` function to call the `add_one` function, as in [Listing 14-7][Listing-14-7]:
|
||||
|
||||
<span class="filename">Filename: adder/src/main.rs</span>
|
||||
|
||||
[Listing-14-7]: #Listing-14-7
|
||||
<a name="Listing-14-7"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate add_one;
|
||||
|
||||
|
@ -334,3 +337,5 @@ As your project grows, consider using a workspace: it’s easier to understand
|
|||
smaller, individual components than one big blob of code. Furthermore, keeping
|
||||
the crates in a workspace can make coordination between them easier if they are
|
||||
often changed at the same time.
|
||||
|
||||
[Listing-14-7]: ch14-03-cargo-workspaces.html#Listing-14-7
|
||||
|
|
|
@ -31,10 +31,13 @@ to that topic. So what you learn here you’ll apply again in Chapter 17!
|
|||
Before we discuss this use case for `Box<T>`, we’ll cover the syntax and how to
|
||||
interact with values stored within a `Box<T>`.
|
||||
|
||||
Listing 15-1 shows how to use a box to store an `i32` value on the heap:
|
||||
[Listing 15-1][Listing-15-1] shows how to use a box to store an `i32` value on the heap:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-1]: #Listing-15-1
|
||||
<a name="Listing-15-1"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let b = Box::new(5);
|
||||
|
@ -100,12 +103,15 @@ complex recursive data types *are* useful in various situations, but by
|
|||
starting with the cons list, we can explore how boxes let us define a recursive
|
||||
data type without much distraction.
|
||||
|
||||
Listing 15-2 contains an enum definition for a cons list. Note that this code
|
||||
[Listing 15-2][Listing-15-2] contains an enum definition for a cons list. Note that this code
|
||||
won’t compile yet because the `List` type doesn’t have a known size, which
|
||||
we’ll demonstrate.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-2]: #Listing-15-2
|
||||
<a name="Listing-15-2"></a>
|
||||
|
||||
```rust,ignore
|
||||
enum List {
|
||||
Cons(i32, List),
|
||||
|
@ -122,10 +128,13 @@ represent a cons list data structure of `i32` values</span>
|
|||
> any type.
|
||||
|
||||
Using the `List` type to store the list `1, 2, 3` would look like the code in
|
||||
Listing 15-3:
|
||||
[Listing 15-3][Listing-15-3]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-3]: #Listing-15-3
|
||||
<a name="Listing-15-3"></a>
|
||||
|
||||
```rust,ignore
|
||||
use List::{Cons, Nil};
|
||||
|
||||
|
@ -142,8 +151,11 @@ another `Cons` value that holds `2` and another `List` value. This `List` value
|
|||
is one more `Cons` value that holds `3` and a `List` value, which is finally
|
||||
`Nil`, the non-recursive variant that signals the end of the list.
|
||||
|
||||
If we try to compile the code in Listing 15-3, we get the error shown in
|
||||
Listing 15-4:
|
||||
If we try to compile the code in [Listing 15-3][Listing-15-3], we get the error shown in
|
||||
[Listing 15-4][Listing-15-4]:
|
||||
|
||||
[Listing-15-4]: #Listing-15-4
|
||||
<a name="Listing-15-4"></a>
|
||||
|
||||
```text
|
||||
error[E0072]: recursive type `List` has infinite size
|
||||
|
@ -170,7 +182,7 @@ type.
|
|||
|
||||
#### Computing the Size of a Non-Recursive Type
|
||||
|
||||
Recall the `Message` enum we defined in Listing 6-2 when we discussed enum
|
||||
Recall the `Message` enum we defined in [Listing 6-2][Listing-6-2] when we discussed enum
|
||||
definitions in Chapter 6:
|
||||
|
||||
```rust
|
||||
|
@ -190,13 +202,16 @@ used, the most space a `Message` value will need is the space it would take to
|
|||
store the largest of its variants.
|
||||
|
||||
Contrast this with what happens when Rust tries to determine how much space a
|
||||
recursive type like the `List` enum in Listing 15-2 needs. The compiler starts
|
||||
recursive type like the `List` enum in [Listing 15-2][Listing-15-2] needs. The compiler starts
|
||||
by looking at the `Cons` variant, which holds a value of type `i32` and a value
|
||||
of type `List`. Therefore, `Cons` needs an amount of space equal to the size of
|
||||
an `i32` plus the size of a `List`. To figure out how much memory the `List`
|
||||
type needs, the compiler looks at the variants, starting with the `Cons`
|
||||
variant. The `Cons` variant holds a value of type `i32` and a value of type
|
||||
`List`, and this process continues infinitely, as shown in Figure 15-1.
|
||||
`List`, and this process continues infinitely, as shown in [Figure 15-1][Figure-15-1].
|
||||
|
||||
[Figure-15-1]: #Figure-15-1
|
||||
<a name="Figure-15-1"></a>
|
||||
|
||||
<img alt="An infinite Cons list" src="img/trpl15-01.svg" class="center" style="width: 50%;" />
|
||||
|
||||
|
@ -206,7 +221,7 @@ variant. The `Cons` variant holds a value of type `i32` and a value of type
|
|||
#### Using `Box<T>` to Get a Recursive Type with a Known Size
|
||||
|
||||
Rust can’t figure out how much space to allocate for recursively defined types,
|
||||
so the compiler gives the error in Listing 15-4. But the error does include
|
||||
so the compiler gives the error in [Listing 15-4][Listing-15-4]. But the error does include
|
||||
this helpful suggestion:
|
||||
|
||||
```text
|
||||
|
@ -227,11 +242,14 @@ Conceptually, we still have a list, created with lists “holding” other lists
|
|||
but this implementation is now more like placing the items next to one another
|
||||
rather than inside one another.
|
||||
|
||||
We can change the definition of the `List` enum in Listing 15-2 and the usage
|
||||
of the `List` in Listing 15-3 to the code in Listing 15-5, which will compile:
|
||||
We can change the definition of the `List` enum in [Listing 15-2][Listing-15-2] and the usage
|
||||
of the `List` in [Listing 15-3][Listing-15-3] to the code in [Listing 15-5][Listing-15-5], which will compile:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-5]: #Listing-15-5
|
||||
<a name="Listing-15-5"></a>
|
||||
|
||||
```rust
|
||||
enum List {
|
||||
Cons(i32, Box<List>),
|
||||
|
@ -256,9 +274,12 @@ box’s pointer data. The `Nil` variant stores no values, so it needs less space
|
|||
than the `Cons` variant. We now know that any `List` value will take up the
|
||||
size of an `i32` plus the size of a box’s pointer data. By using a box, we’ve
|
||||
broken the infinite, recursive chain, so the compiler can figure out the size
|
||||
it needs to store a `List` value. Figure 15-2 shows what the `Cons` variant
|
||||
it needs to store a `List` value. [Figure 15-2][Figure-15-2] shows what the `Cons` variant
|
||||
looks like now.
|
||||
|
||||
[Figure-15-2]: #Figure-15-2
|
||||
<a name="Figure-15-2"></a>
|
||||
|
||||
<img alt="A finite Cons list" src="img/trpl15-02.svg" class="center" />
|
||||
|
||||
<span class="caption">Figure 15-2: A `List` that is not infinitely sized
|
||||
|
@ -278,3 +299,12 @@ up as well because of the `Drop` trait implementation. Let’s explore these two
|
|||
traits in more detail. These two traits will be even more important to the
|
||||
functionality provided by the other smart pointer types we’ll discuss in the
|
||||
rest of this chapter.
|
||||
|
||||
[Listing-15-1]: ch15-01-box.html#Listing-15-1
|
||||
[Listing-15-2]: ch15-01-box.html#Listing-15-2
|
||||
[Listing-15-3]: ch15-01-box.html#Listing-15-3
|
||||
[Listing-15-4]: ch15-01-box.html#Listing-15-4
|
||||
[Figure-15-1]: ch15-01-box.html#Figure-15-1
|
||||
[Listing-15-5]: ch15-01-box.html#Listing-15-5
|
||||
[Figure-15-2]: ch15-01-box.html#Figure-15-2
|
||||
[Listing-6-2]: ch06-01-defining-an-enum.html#Listing-6-2
|
||||
|
|
|
@ -17,12 +17,15 @@ or smart pointers.
|
|||
### Following the Pointer to the Value with the Dereference Operator
|
||||
|
||||
A regular reference is a type of pointer, and one way to think of a pointer is
|
||||
as an arrow to a value stored somewhere else. In Listing 15-6, we create a
|
||||
as an arrow to a value stored somewhere else. In [Listing 15-6][Listing-15-6], we create a
|
||||
reference to an `i32` value and then use the dereference operator to follow the
|
||||
reference to the data:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-6]: #Listing-15-6
|
||||
<a name="Listing-15-6"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = 5;
|
||||
|
@ -64,11 +67,14 @@ to the value it’s pointing to.
|
|||
|
||||
### Using `Box<T>` Like a Reference
|
||||
|
||||
We can rewrite the code in Listing 15-6 to use a `Box<T>` instead of a
|
||||
reference; the dereference operator will work as shown in Listing 15-7:
|
||||
We can rewrite the code in [Listing 15-6][Listing-15-6] to use a `Box<T>` instead of a
|
||||
reference; the dereference operator will work as shown in [Listing 15-7][Listing-15-7]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-7]: #Listing-15-7
|
||||
<a name="Listing-15-7"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = 5;
|
||||
|
@ -82,7 +88,7 @@ fn main() {
|
|||
<span class="caption">Listing 15-7: Using the dereference operator on a
|
||||
`Box<i32>`</span>
|
||||
|
||||
The only difference between Listing 15-7 and Listing 15-6 is that here we set
|
||||
The only difference between [Listing 15-7][Listing-15-7] and [Listing 15-6][Listing-15-6] is that here we set
|
||||
`y` to be an instance of a box pointing to the value in `x` rather than a
|
||||
reference pointing to the value of `x`. In the last assertion, we can use the
|
||||
dereference operator to follow the box’s pointer in the same way that we did
|
||||
|
@ -97,11 +103,14 @@ references by default. Then we’ll look at how to add the ability to use the
|
|||
dereference operator.
|
||||
|
||||
The `Box<T>` type is ultimately defined as a tuple struct with one element, so
|
||||
Listing 15-8 defines a `MyBox<T>` type in the same way. We’ll also define a
|
||||
[Listing 15-8][Listing-15-8] defines a `MyBox<T>` type in the same way. We’ll also define a
|
||||
`new` function to match the `new` function defined on `Box<T>`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-8]: #Listing-15-8
|
||||
<a name="Listing-15-8"></a>
|
||||
|
||||
```rust
|
||||
struct MyBox<T>(T);
|
||||
|
||||
|
@ -119,13 +128,16 @@ we want our type to hold values of any type. The `MyBox` type is a tuple struct
|
|||
with one element of type `T`. The `MyBox::new` function takes one parameter of
|
||||
type `T` and returns a `MyBox` instance that holds the value passed in.
|
||||
|
||||
Let’s try adding the `main` function in Listing 15-7 to Listing 15-8 and
|
||||
Let’s try adding the `main` function in [Listing 15-7][Listing-15-7] to [Listing 15-8][Listing-15-8] and
|
||||
changing it to use the `MyBox<T>` type we’ve defined instead of `Box<T>`. The
|
||||
code in Listing 15-9 won’t compile because Rust doesn’t know how to dereference
|
||||
code in [Listing 15-9][Listing-15-9] won’t compile because Rust doesn’t know how to dereference
|
||||
`MyBox`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-9]: #Listing-15-9
|
||||
<a name="Listing-15-9"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let x = 5;
|
||||
|
@ -158,11 +170,14 @@ implement the `Deref` trait.
|
|||
As discussed in Chapter 10, to implement a trait, we need to provide
|
||||
implementations for the trait’s required methods. The `Deref` trait, provided
|
||||
by the standard library, requires us to implement one method named `deref` that
|
||||
borrows `self` and returns a reference to the inner data. Listing 15-10
|
||||
borrows `self` and returns a reference to the inner data. [Listing 15-10][Listing-15-10]
|
||||
contains an implementation of `Deref` to add to the definition of `MyBox`:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-10]: #Listing-15-10
|
||||
<a name="Listing-15-10"></a>
|
||||
|
||||
```rust
|
||||
use std::ops::Deref;
|
||||
|
||||
|
@ -185,7 +200,7 @@ more detail in Chapter 19.
|
|||
|
||||
We fill in the body of the `deref` method with `&self.0` so `deref` returns a
|
||||
reference to the value we want to access with the `*` operator. The `main`
|
||||
function in Listing 15-9 that calls `*` on the `MyBox<T>` value now compiles,
|
||||
function in [Listing 15-9][Listing-15-9] that calls `*` on the `MyBox<T>` value now compiles,
|
||||
and the assertions pass!
|
||||
|
||||
Without the `Deref` trait, the compiler can only dereference `&` references.
|
||||
|
@ -193,7 +208,7 @@ The `deref` method gives the compiler the ability to take a value of any type
|
|||
that implements `Deref` and call the `deref` method to get a `&` reference that
|
||||
it knows how to dereference.
|
||||
|
||||
When we entered `*y` in Listing 15-9, behind the scenes Rust actually ran this
|
||||
When we entered `*y` in [Listing 15-9][Listing-15-9], behind the scenes Rust actually ran this
|
||||
code:
|
||||
|
||||
```rust,ignore
|
||||
|
@ -217,7 +232,7 @@ Note that the `*` operator is replaced with a call to the `deref` method and
|
|||
then a call to the `*` operator just once, each time we use a `*` in our code.
|
||||
Because the substitution of the `*` operator does not recurse infinitely, we
|
||||
end up with data of type `i32`, which matches the `5` in `assert_eq!` in
|
||||
Listing 15-9.
|
||||
[Listing 15-9][Listing-15-9].
|
||||
|
||||
### Implicit Deref Coercions with Functions and Methods
|
||||
|
||||
|
@ -236,12 +251,15 @@ with `&` and `*`. The deref coercion feature also lets us write more code that
|
|||
can work for either references or smart pointers.
|
||||
|
||||
To see deref coercion in action, let’s use the `MyBox<T>` type we defined in
|
||||
Listing 15-8 as well as the implementation of `Deref` that we added in Listing
|
||||
15-10. Listing 15-11 shows the definition of a function that has a string slice
|
||||
[Listing 15-8][Listing-15-8] as well as the implementation of `Deref` that we added in [Listing 15-10][Listing-15-10].
|
||||
[Listing 15-11][Listing-15-11] shows the definition of a function that has a string slice
|
||||
parameter:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-11]: #Listing-15-11
|
||||
<a name="Listing-15-11"></a>
|
||||
|
||||
```rust
|
||||
fn hello(name: &str) {
|
||||
println!("Hello, {}!", name);
|
||||
|
@ -253,10 +271,13 @@ fn hello(name: &str) {
|
|||
|
||||
We can call the `hello` function with a string slice as an argument, such as
|
||||
`hello("Rust");` for example. Deref coercion makes it possible to call `hello`
|
||||
with a reference to a value of type `MyBox<String>`, as shown in Listing 15-12:
|
||||
with a reference to a value of type `MyBox<String>`, as shown in [Listing 15-12][Listing-15-12]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-12]: #Listing-15-12
|
||||
<a name="Listing-15-12"></a>
|
||||
|
||||
```rust
|
||||
# use std::ops::Deref;
|
||||
#
|
||||
|
@ -291,18 +312,21 @@ fn main() {
|
|||
|
||||
Here we’re calling the `hello` function with the argument `&m`, which is a
|
||||
reference to a `MyBox<String>` value. Because we implemented the `Deref` trait
|
||||
on `MyBox<T>` in Listing 15-10, Rust can turn `&MyBox<String>` into `&String`
|
||||
on `MyBox<T>` in [Listing 15-10][Listing-15-10], Rust can turn `&MyBox<String>` into `&String`
|
||||
by calling `deref`. The standard library provides an implementation of `Deref`
|
||||
on `String` that returns a string slice, and this is in the API documentation
|
||||
for `Deref`. Rust calls `deref` again to turn the `&String` into `&str`, which
|
||||
matches the `hello` function’s definition.
|
||||
|
||||
If Rust didn’t implement deref coercion, we would have to write the code in
|
||||
Listing 15-13 instead of the code in Listing 15-12 to call `hello` with a value
|
||||
[Listing 15-13][Listing-15-13] instead of the code in [Listing 15-12][Listing-15-12] to call `hello` with a value
|
||||
of type `&MyBox<String>`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-13]: #Listing-15-13
|
||||
<a name="Listing-15-13"></a>
|
||||
|
||||
```rust
|
||||
# use std::ops::Deref;
|
||||
#
|
||||
|
@ -375,3 +399,12 @@ Converting an immutable reference to a mutable reference would require that
|
|||
there is only one immutable reference to that data, and the borrowing rules
|
||||
don’t guarantee that. Therefore, Rust can’t make the assumption that converting
|
||||
an immutable reference to a mutable reference is possible.
|
||||
|
||||
[Listing-15-6]: ch15-02-deref.html#Listing-15-6
|
||||
[Listing-15-7]: ch15-02-deref.html#Listing-15-7
|
||||
[Listing-15-8]: ch15-02-deref.html#Listing-15-8
|
||||
[Listing-15-9]: ch15-02-deref.html#Listing-15-9
|
||||
[Listing-15-10]: ch15-02-deref.html#Listing-15-10
|
||||
[Listing-15-11]: ch15-02-deref.html#Listing-15-11
|
||||
[Listing-15-12]: ch15-02-deref.html#Listing-15-12
|
||||
[Listing-15-13]: ch15-02-deref.html#Listing-15-13
|
||||
|
|
|
@ -22,13 +22,16 @@ Specify the code to run when a value goes out of scope by implementing the
|
|||
`drop` that takes a mutable reference to `self`. To see when Rust calls `drop`,
|
||||
let’s implement `drop` with `println!` statements for now.
|
||||
|
||||
Listing 15-14 shows a `CustomSmartPointer` struct whose only custom
|
||||
[Listing 15-14][Listing-15-14] shows a `CustomSmartPointer` struct whose only custom
|
||||
functionality is that it will print `Dropping CustomSmartPointer!` when the
|
||||
instance goes out of scope. This example demonstrates when Rust runs the `drop`
|
||||
function.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-14]: #Listing-15-14
|
||||
<a name="Listing-15-14"></a>
|
||||
|
||||
```rust
|
||||
struct CustomSmartPointer {
|
||||
data: String,
|
||||
|
@ -90,11 +93,14 @@ you have to call the `std::mem::drop` function provided by the standard library
|
|||
if you want to force a value to be dropped before the end of its scope.
|
||||
|
||||
If we try to call the `Drop` trait’s `drop` method manually by modifying the
|
||||
`main` function from Listing 15-14, as shown in Listing 15-15, we’ll get a
|
||||
`main` function from [Listing 15-14][Listing-15-14], as shown in [Listing 15-15][Listing-15-15], we’ll get a
|
||||
compiler error:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-15]: #Listing-15-15
|
||||
<a name="Listing-15-15"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let c = CustomSmartPointer { data: String::from("some data") };
|
||||
|
@ -134,11 +140,14 @@ a value to be cleaned up early, we can use the `std::mem::drop` function.
|
|||
|
||||
The `std::mem::drop` function is different than the `drop` method in the `Drop`
|
||||
trait. We call it by passing the value we want to force to be dropped early as
|
||||
an argument. The function is in the prelude, so we can modify `main` in Listing
|
||||
15-15 to call the `drop` function, as shown in Listing 15-16:
|
||||
an argument. The function is in the prelude, so we can modify `main` in [Listing 15-15][Listing-15-15]
|
||||
to call the `drop` function, as shown in [Listing 15-16][Listing-15-16]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-16]: #Listing-15-16
|
||||
<a name="Listing-15-16"></a>
|
||||
|
||||
```rust
|
||||
# struct CustomSmartPointer {
|
||||
# data: String,
|
||||
|
@ -187,3 +196,7 @@ the value is no longer being used.
|
|||
Now that we’ve examined `Box<T>` and some of the characteristics of smart
|
||||
pointers, let’s look at a few other smart pointers defined in the standard
|
||||
library.
|
||||
|
||||
[Listing-15-14]: ch15-03-drop.html#Listing-15-14
|
||||
[Listing-15-15]: ch15-03-drop.html#Listing-15-15
|
||||
[Listing-15-16]: ch15-03-drop.html#Listing-15-16
|
||||
|
|
|
@ -31,9 +31,12 @@ multithreaded programs.
|
|||
|
||||
### Using `Rc<T>` to Share Data
|
||||
|
||||
Let’s return to our cons list example in Listing 15-5. Recall that we defined
|
||||
Let’s return to our cons list example in [Listing 15-5][Listing-15-5]. Recall that we defined
|
||||
it using `Box<T>`. This time, we’ll create two lists that both share ownership
|
||||
of a third list. Conceptually, this looks similar to Figure 15-3:
|
||||
of a third list. Conceptually, this looks similar to [Figure 15-3][Figure-15-3]:
|
||||
|
||||
[Figure-15-3]: #Figure-15-3
|
||||
<a name="Figure-15-3"></a>
|
||||
|
||||
<img alt="Two lists that share ownership of a third list" src="img/trpl15-03.svg" class="center" />
|
||||
|
||||
|
@ -46,10 +49,13 @@ lists will then continue on to the first `a` list containing 5 and 10. In other
|
|||
words, both lists will share the first list containing 5 and 10.
|
||||
|
||||
Trying to implement this scenario using our definition of `List` with `Box<T>`
|
||||
won’t work, as shown in Listing 15-17:
|
||||
won’t work, as shown in [Listing 15-17][Listing-15-17]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-17]: #Listing-15-17
|
||||
<a name="Listing-15-17"></a>
|
||||
|
||||
```rust,ignore
|
||||
enum List {
|
||||
Cons(i32, Box<List>),
|
||||
|
@ -97,7 +103,7 @@ least as long as the entire list. The borrow checker wouldn’t let us compile
|
|||
be dropped before `a` could take a reference to it.
|
||||
|
||||
Instead, we’ll change our definition of `List` to use `Rc<T>` in place of
|
||||
`Box<T>`, as shown in Listing 15-18. Each `Cons` variant will now hold a value
|
||||
`Box<T>`, as shown in [Listing 15-18][Listing-15-18]. Each `Cons` variant will now hold a value
|
||||
and an `Rc<T>` pointing to a `List`. When we create `b`, instead of taking
|
||||
ownership of `a`, we’ll clone the `Rc<List>` that `a` is holding, thereby
|
||||
increasing the number of references from one to two and letting `a` and `b`
|
||||
|
@ -109,6 +115,9 @@ it.
|
|||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-18]: #Listing-15-18
|
||||
<a name="Listing-15-18"></a>
|
||||
|
||||
```rust
|
||||
enum List {
|
||||
Cons(i32, Rc<List>),
|
||||
|
@ -147,14 +156,17 @@ code, we only need to consider the deep-copy clones and can disregard calls to
|
|||
|
||||
### Cloning an `Rc<T>` Increases the Reference Count
|
||||
|
||||
Let’s change our working example in Listing 15-18 so we can see the reference
|
||||
Let’s change our working example in [Listing 15-18][Listing-15-18] so we can see the reference
|
||||
counts changing as we create and drop references to the `Rc<List>` in `a`.
|
||||
|
||||
In Listing 15-19, we’ll change `main` so it has an inner scope around list `c`;
|
||||
In [Listing 15-19][Listing-15-19], we’ll change `main` so it has an inner scope around list `c`;
|
||||
then we can see how the reference count changes when `c` goes out of scope.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-19]: #Listing-15-19
|
||||
<a name="Listing-15-19"></a>
|
||||
|
||||
```rust
|
||||
# enum List {
|
||||
# Cons(i32, Rc<List>),
|
||||
|
@ -215,3 +227,9 @@ and inconsistencies. But being able to mutate data is very useful! In the next
|
|||
section, we’ll discuss the interior mutability pattern and the `RefCell<T>`
|
||||
type that you can use in conjunction with an `Rc<T>` to work with this
|
||||
immutability restriction.
|
||||
|
||||
[Listing-15-5]: ch15-01-box.html#Listing-15-5
|
||||
[Figure-15-3]: ch15-04-rc.html#Figure-15-3
|
||||
[Listing-15-17]: ch15-04-rc.html#Listing-15-17
|
||||
[Listing-15-18]: ch15-04-rc.html#Listing-15-18
|
||||
[Listing-15-19]: ch15-04-rc.html#Listing-15-19
|
||||
|
|
|
@ -131,10 +131,13 @@ that use our library will be expected to provide the mechanism for sending the
|
|||
messages: the application could put a message in the application, send an
|
||||
email, send a text message, or something else. The library doesn’t need to know
|
||||
that detail. All it needs is something that implements a trait we’ll provide
|
||||
called `Messenger`. Listing 15-20 shows the library code:
|
||||
called `Messenger`. [Listing 15-20][Listing-15-20] shows the library code:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-15-20]: #Listing-15-20
|
||||
<a name="Listing-15-20"></a>
|
||||
|
||||
```rust
|
||||
pub trait Messenger {
|
||||
fn send(&self, msg: &str);
|
||||
|
@ -190,11 +193,14 @@ We need a mock object that, instead of sending an email or text message when we
|
|||
call `send`, will only keep track of the messages it’s told to send. We can
|
||||
create a new instance of the mock object, create a `LimitTracker` that uses the
|
||||
mock object, call the `set_value` method on `LimitTracker`, and then check that
|
||||
the mock object has the messages we expect. Listing 15-21 shows an attempt to
|
||||
the mock object has the messages we expect. [Listing 15-21][Listing-15-21] shows an attempt to
|
||||
implement a mock object to do just that, but the borrow checker won’t allow it:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-15-21]: #Listing-15-21
|
||||
<a name="Listing-15-21"></a>
|
||||
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
@ -269,11 +275,14 @@ definition (feel free to try and see what error message you get).
|
|||
|
||||
This is a situation in which interior mutability can help! We’ll store the
|
||||
`sent_messages` within a `RefCell<T>`, and then the `send` message will be
|
||||
able to modify `sent_messages` to store the messages we’ve seen. Listing 15-22
|
||||
able to modify `sent_messages` to store the messages we’ve seen. [Listing 15-22][Listing-15-22]
|
||||
shows what that looks like:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-15-22]: #Listing-15-22
|
||||
<a name="Listing-15-22"></a>
|
||||
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
@ -346,13 +355,16 @@ borrows or one mutable borrow at any point in time.
|
|||
|
||||
If we try to violate these rules, rather than getting a compiler error as we
|
||||
would with references, the implementation of `RefCell<T>` will panic at
|
||||
runtime. Listing 15-23 shows a modification of the implementation of `send` in
|
||||
Listing 15-22. We’re deliberately trying to create two mutable borrows active
|
||||
runtime. [Listing 15-23][Listing-15-23] shows a modification of the implementation of `send` in
|
||||
[Listing 15-22][Listing-15-22]. We’re deliberately trying to create two mutable borrows active
|
||||
for the same scope to illustrate that `RefCell<T>` prevents us from doing this
|
||||
at runtime.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-15-23]: #Listing-15-23
|
||||
<a name="Listing-15-23"></a>
|
||||
|
||||
```rust,ignore
|
||||
impl Messenger for MockMessenger {
|
||||
fn send(&self, message: &str) {
|
||||
|
@ -371,8 +383,8 @@ same scope to see that `RefCell<T>` will panic</span>
|
|||
We create a variable `one_borrow` for the `RefMut<T>` smart pointer returned
|
||||
from `borrow_mut`. Then we create another mutable borrow in the same way in the
|
||||
variable `two_borrow`. This makes two mutable references in the same scope,
|
||||
which isn’t allowed. When we run the tests for our library, the code in Listing
|
||||
15-23 will compile without any errors, but the test will fail:
|
||||
which isn’t allowed. When we run the tests for our library, the code in [Listing 15-23][Listing-15-23]
|
||||
will compile without any errors, but the test will fail:
|
||||
|
||||
```text
|
||||
---- tests::it_sends_an_over_75_percent_warning_message stdout ----
|
||||
|
@ -402,16 +414,19 @@ A common way to use `RefCell<T>` is in combination with `Rc<T>`. Recall that
|
|||
access to that data. If you have an `Rc<T>` that holds a `RefCell<T>`, you can
|
||||
get a value that can have multiple owners *and* that you can mutate!
|
||||
|
||||
For example, recall the cons list example in Listing 15-18 where we used
|
||||
For example, recall the cons list example in [Listing 15-18][Listing-15-18] where we used
|
||||
`Rc<T>` to allow multiple lists to share ownership of another list. Because
|
||||
`Rc<T>` holds only immutable values, we can’t change any of the values in the
|
||||
list once we’ve created them. Let’s add in `RefCell<T>` to gain the ability to
|
||||
change the values in the lists. Listing 15-24 shows that by using a
|
||||
change the values in the lists. [Listing 15-24][Listing-15-24] shows that by using a
|
||||
`RefCell<T>` in the `Cons` definition, we can modify the value stored in all
|
||||
the lists:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-24]: #Listing-15-24
|
||||
<a name="Listing-15-24"></a>
|
||||
|
||||
```rust
|
||||
#[derive(Debug)]
|
||||
enum List {
|
||||
|
@ -450,7 +465,7 @@ than transferring ownership from `value` to `a` or having `a` borrow from
|
|||
`value`.
|
||||
|
||||
We wrap the list `a` in an `Rc<T>` so when we create lists `b` and `c`, they
|
||||
can both refer to `a`, which is what we did in Listing 15-18.
|
||||
can both refer to `a`, which is what we did in [Listing 15-18][Listing-15-18].
|
||||
|
||||
After we’ve created the lists in `a`, `b`, and `c`, we add 10 to the value in
|
||||
`value`. We do this by calling `borrow_mut` on `value`, which uses the
|
||||
|
@ -481,3 +496,10 @@ inner value, the value is copied in and out of the `Cell<T>`. There’s also
|
|||
`Mutex<T>`, which offers interior mutability that’s safe to use across threads;
|
||||
we’ll discuss its use in Chapter 16. Check out the standard library docs for
|
||||
more details on the differences between these types.
|
||||
|
||||
[Listing-15-20]: ch15-05-interior-mutability.html#Listing-15-20
|
||||
[Listing-15-21]: ch15-05-interior-mutability.html#Listing-15-21
|
||||
[Listing-15-22]: ch15-05-interior-mutability.html#Listing-15-22
|
||||
[Listing-15-23]: ch15-05-interior-mutability.html#Listing-15-23
|
||||
[Listing-15-24]: ch15-05-interior-mutability.html#Listing-15-24
|
||||
[Listing-15-18]: ch15-04-rc.html#Listing-15-18
|
||||
|
|
|
@ -12,14 +12,16 @@ item in the cycle will never reach 0, and the values will never be dropped.
|
|||
### Creating a Reference Cycle
|
||||
|
||||
Let’s look at how a reference cycle might happen and how to prevent it,
|
||||
starting with the definition of the `List` enum and a `tail` method in Listing
|
||||
15-25:
|
||||
starting with the definition of the `List` enum and a `tail` method in [Listing 15-25][Listing-15-25]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
<!-- Hidden fn main is here to disable the automatic wrapping in fn main that
|
||||
doc tests do; the `use List` fails if this listing is put within a main -->
|
||||
|
||||
[Listing-15-25]: #Listing-15-25
|
||||
<a name="Listing-15-25"></a>
|
||||
|
||||
```rust
|
||||
# fn main() {}
|
||||
use std::rc::Rc;
|
||||
|
@ -45,21 +47,24 @@ impl List {
|
|||
<span class="caption">Listing 15-25: A cons list definition that holds a
|
||||
`RefCell<T>` so we can modify what a `Cons` variant is referring to</span>
|
||||
|
||||
We’re using another variation of the `List` definition in Listing 15-5. The
|
||||
We’re using another variation of the `List` definition in [Listing 15-5][Listing-15-5]. The
|
||||
second element in the `Cons` variant is now `RefCell<Rc<List>>`, meaning that
|
||||
instead of having the ability to modify the `i32` value as we did in Listing
|
||||
15-24, we want to modify which `List` value a `Cons` variant is pointing to.
|
||||
instead of having the ability to modify the `i32` value as we did in [Listing 15-24][Listing-15-24],
|
||||
we want to modify which `List` value a `Cons` variant is pointing to.
|
||||
We’re also adding a `tail` method to make it convenient for us to access the
|
||||
second item if we have a `Cons` variant.
|
||||
|
||||
In Listing 15-26, we’re adding a `main` function that uses the definitions in
|
||||
Listing 15-25. This code creates a list in `a` and a list in `b` that points to
|
||||
In [Listing 15-26][Listing-15-26], we’re adding a `main` function that uses the definitions in
|
||||
[Listing 15-25][Listing-15-25]. This code creates a list in `a` and a list in `b` that points to
|
||||
the list in `a`. Then it modifies the list in `a` to point to `b`, creating a
|
||||
reference cycle. There are `println!` statements along the way to show what the
|
||||
reference counts are at various points in this process.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-26]: #Listing-15-26
|
||||
<a name="Listing-15-26"></a>
|
||||
|
||||
```rust
|
||||
# use List::{Cons, Nil};
|
||||
# use std::rc::Rc;
|
||||
|
@ -139,8 +144,10 @@ will try to drop `b` first, which will decrease the count in each of the
|
|||
However, because `a` is still referencing the `Rc<List>` that was in `b`, that
|
||||
`Rc<List>` has a count of 1 rather than 0, so the memory the `Rc<List>` has on
|
||||
the heap won’t be dropped. The memory will just sit there with a count of 1,
|
||||
forever. To visualize this reference cycle, we’ve created a diagram in Figure
|
||||
15-4.
|
||||
forever. To visualize this reference cycle, we’ve created a diagram in [Figure 15-4][Figure-15-4].
|
||||
|
||||
[Figure-15-4]: #Figure-15-4
|
||||
<a name="Figure-15-4"></a>
|
||||
|
||||
<img alt="Reference cycle of lists" src="img/trpl15-04.svg" class="center" />
|
||||
|
||||
|
@ -169,7 +176,7 @@ Another solution for avoiding reference cycles is reorganizing your data
|
|||
structures so that some references express ownership and some references don’t.
|
||||
As a result, you can have cycles made up of some ownership relationships and
|
||||
some non-ownership relationships, and only the ownership relationships affect
|
||||
whether or not a value can be dropped. In Listing 15-25, we always want `Cons`
|
||||
whether or not a value can be dropped. In [Listing 15-25][Listing-15-25], we always want `Cons`
|
||||
variants to own their list, so reorganizing the data structure isn’t possible.
|
||||
Let’s look at an example using graphs made up of parent nodes and child nodes
|
||||
to see when non-ownership relationships are an appropriate way to prevent
|
||||
|
@ -233,10 +240,13 @@ modify which nodes are children of another node, so we have a `RefCell<T>` in
|
|||
|
||||
Next, we’ll use our struct definition and create one `Node` instance named
|
||||
`leaf` with the value 3 and no children, and another instance named `branch`
|
||||
with the value 5 and `leaf` as one of its children, as shown in Listing 15-27:
|
||||
with the value 5 and `leaf` as one of its children, as shown in [Listing 15-27][Listing-15-27]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-27]: #Listing-15-27
|
||||
<a name="Listing-15-27"></a>
|
||||
|
||||
```rust
|
||||
# use std::rc::Rc;
|
||||
# use std::cell::RefCell;
|
||||
|
@ -303,11 +313,14 @@ struct Node {
|
|||
```
|
||||
|
||||
A node will be able to refer to its parent node but doesn’t own its parent.
|
||||
In Listing 15-28, we update `main` to use this new definition so the `leaf`
|
||||
In [Listing 15-28][Listing-15-28], we update `main` to use this new definition so the `leaf`
|
||||
node will have a way to refer to its parent, `branch`:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-28]: #Listing-15-28
|
||||
<a name="Listing-15-28"></a>
|
||||
|
||||
```rust
|
||||
# use std::rc::{Rc, Weak};
|
||||
# use std::cell::RefCell;
|
||||
|
@ -344,7 +357,7 @@ fn main() {
|
|||
parent node `branch`</span>
|
||||
|
||||
Creating the `leaf` node looks similar to how creating the `leaf` node looked
|
||||
in Listing 15-27 with the exception of the `parent` field: `leaf` starts out
|
||||
in [Listing 15-27][Listing-15-27] with the exception of the `parent` field: `leaf` starts out
|
||||
without a parent, so we create a new, empty `Weak<Node>` reference instance.
|
||||
|
||||
At this point, when we try to get a reference to the parent of `leaf` by using
|
||||
|
@ -367,7 +380,7 @@ the `Rc<Node>` in `branch.`
|
|||
When we print the parent of `leaf` again, this time we’ll get a `Some` variant
|
||||
holding `branch`: now `leaf` can access its parent! When we print `leaf`, we
|
||||
also avoid the cycle that eventually ended in a stack overflow like we had in
|
||||
Listing 15-26; the `Weak<Node>` references are printed as `(Weak)`:
|
||||
[Listing 15-26][Listing-15-26]; the `Weak<Node>` references are printed as `(Weak)`:
|
||||
|
||||
```text
|
||||
leaf parent = Some(Node { value: 5, parent: RefCell { value: (Weak) },
|
||||
|
@ -385,10 +398,13 @@ Let’s look at how the `strong_count` and `weak_count` values of the `Rc<Node>`
|
|||
instances change by creating a new inner scope and moving the creation of
|
||||
`branch` into that scope. By doing so, we can see what happens when `branch` is
|
||||
created and then dropped when it goes out of scope. The modifications are shown
|
||||
in Listing 15-29:
|
||||
in [Listing 15-29][Listing-15-29]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-15-29]: #Listing-15-29
|
||||
<a name="Listing-15-29"></a>
|
||||
|
||||
```rust
|
||||
# use std::rc::{Rc, Weak};
|
||||
# use std::cell::RefCell;
|
||||
|
@ -496,3 +512,12 @@ information.
|
|||
|
||||
Next, we’ll talk about concurrency in Rust. You’ll even learn about a few new
|
||||
smart pointers.
|
||||
|
||||
[Listing-15-24]: ch15-05-interior-mutability.html#Listing-15-24
|
||||
[Listing-15-5]: ch15-01-box.html#Listing-15-5
|
||||
[Listing-15-25]: ch15-06-reference-cycles.html#Listing-15-25
|
||||
[Listing-15-26]: ch15-06-reference-cycles.html#Listing-15-26
|
||||
[Figure-15-4]: ch15-06-reference-cycles.html#Figure-15-4
|
||||
[Listing-15-27]: ch15-06-reference-cycles.html#Listing-15-27
|
||||
[Listing-15-28]: ch15-06-reference-cycles.html#Listing-15-28
|
||||
[Listing-15-29]: ch15-06-reference-cycles.html#Listing-15-29
|
||||
|
|
|
@ -65,11 +65,14 @@ thread-related API provided by the standard library.
|
|||
|
||||
To create a new thread, we call the `thread::spawn` function and pass it a
|
||||
closure (we talked about closures in Chapter 13) containing the code we want to
|
||||
run in the new thread. The example in Listing 16-1 prints some text from a main
|
||||
run in the new thread. The example in [Listing 16-1][Listing-16-1] prints some text from a main
|
||||
thread and other text from a new thread:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-1]: #Listing-16-1
|
||||
<a name="Listing-16-1"></a>
|
||||
|
||||
```rust
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
@ -123,7 +126,7 @@ for the operating system to switch between the threads.
|
|||
|
||||
### Waiting for All Threads to Finish Using `join` Handles
|
||||
|
||||
The code in Listing 16-1 not only stops the spawned thread prematurely most of
|
||||
The code in [Listing 16-1][Listing-16-1] not only stops the spawned thread prematurely most of
|
||||
the time due to the main thread ending, but also can’t guarantee that the
|
||||
spawned thread will get to run at all. The reason is that there is no guarantee
|
||||
on the order in which threads run!
|
||||
|
@ -132,12 +135,15 @@ We can fix the problem of the spawned thread not getting to run, or not getting
|
|||
to run completely, by saving the return value of `thread::spawn` in a variable.
|
||||
The return type of `thread::spawn` is `JoinHandle`. A `JoinHandle` is an owned
|
||||
value that, when we call the `join` method on it, will wait for its thread to
|
||||
finish. Listing 16-2 shows how to use the `JoinHandle` of the thread we created
|
||||
in Listing 16-1 and call `join` to make sure the spawned thread finishes before
|
||||
finish. [Listing 16-2][Listing-16-2] shows how to use the `JoinHandle` of the thread we created
|
||||
in [Listing 16-1][Listing-16-1] and call `join` to make sure the spawned thread finishes before
|
||||
`main` exits:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-2]: #Listing-16-2
|
||||
<a name="Listing-16-2"></a>
|
||||
|
||||
```rust
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
@ -165,7 +171,7 @@ to guarantee the thread is run to completion</span>
|
|||
Calling `join` on the handle blocks the thread currently running until the
|
||||
thread represented by the handle terminates. *Blocking* a thread means that
|
||||
thread is prevented from performing work or exiting. Because we’ve put the call
|
||||
to `join` after the main thread’s `for` loop, running Listing 16-2 should
|
||||
to `join` after the main thread’s `for` loop, running [Listing 16-2][Listing-16-2] should
|
||||
produce output similar to this:
|
||||
|
||||
```text
|
||||
|
@ -245,15 +251,18 @@ list of a closure to force the closure to take ownership of the values it uses
|
|||
in the environment. This technique is especially useful when creating new
|
||||
threads in order to transfer ownership of values from one thread to another.
|
||||
|
||||
Notice in Listing 16-1 that the closure we pass to `thread::spawn` takes no
|
||||
Notice in [Listing 16-1][Listing-16-1] that the closure we pass to `thread::spawn` takes no
|
||||
arguments: we’re not using any data from the main thread in the spawned
|
||||
thread’s code. To use data from the main thread in the spawned thread, the
|
||||
spawned thread’s closure must capture the values it needs. Listing 16-3 shows
|
||||
spawned thread’s closure must capture the values it needs. [Listing 16-3][Listing-16-3] shows
|
||||
an attempt to create a vector in the main thread and use it in the spawned
|
||||
thread. However, this won’t yet work, as you’ll see in a moment.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-3]: #Listing-16-3
|
||||
<a name="Listing-16-3"></a>
|
||||
|
||||
```rust,ignore
|
||||
use std::thread;
|
||||
|
||||
|
@ -298,11 +307,14 @@ to `v`, the closure tries to borrow `v`. However, there’s a problem: Rust can
|
|||
tell how long the spawned thread will run, so it doesn’t know if the reference
|
||||
to `v` will always be valid.
|
||||
|
||||
Listing 16-4 provides a scenario that’s more likely to have a reference to `v`
|
||||
[Listing 16-4][Listing-16-4] provides a scenario that’s more likely to have a reference to `v`
|
||||
that won’t be valid:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-4]: #Listing-16-4
|
||||
<a name="Listing-16-4"></a>
|
||||
|
||||
```rust,ignore
|
||||
use std::thread;
|
||||
|
||||
|
@ -329,7 +341,7 @@ thread has a reference to `v` inside, but the main thread immediately drops
|
|||
spawned thread starts to execute, `v` is no longer valid, so a reference to it
|
||||
is also invalid. Oh no!
|
||||
|
||||
To fix the compiler error in Listing 16-3, we can use the error message’s
|
||||
To fix the compiler error in [Listing 16-3][Listing-16-3], we can use the error message’s
|
||||
advice:
|
||||
|
||||
```text
|
||||
|
@ -342,11 +354,14 @@ variables), use the `move` keyword
|
|||
|
||||
By adding the `move` keyword before the closure, we force the closure to take
|
||||
ownership of the values it’s using rather than allowing Rust to infer that it
|
||||
should borrow the values. The modification to Listing 16-3 shown in Listing
|
||||
16-5 will compile and run as we intend:
|
||||
should borrow the values. The modification to [Listing 16-3][Listing-16-3] shown in [Listing 16-5][Listing-16-5]
|
||||
will compile and run as we intend:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-5]: #Listing-16-5
|
||||
<a name="Listing-16-5"></a>
|
||||
|
||||
```rust
|
||||
use std::thread;
|
||||
|
||||
|
@ -364,9 +379,9 @@ fn main() {
|
|||
<span class="caption">Listing 16-5: Using the `move` keyword to force a closure
|
||||
to take ownership of the values it uses</span>
|
||||
|
||||
What would happen to the code in Listing 16-4 where the main thread called
|
||||
What would happen to the code in [Listing 16-4][Listing-16-4] where the main thread called
|
||||
`drop` if we use a `move` closure? Would `move` fix that case? Unfortunately,
|
||||
no; we would get a different error because what Listing 16-4 is trying to do
|
||||
no; we would get a different error because what [Listing 16-4][Listing-16-4] is trying to do
|
||||
isn’t allowed for a different reason. If we added `move` to the closure, we
|
||||
would move `v` into the closure’s environment, and we could no longer call
|
||||
`drop` on it in the main thread. We would get this compiler error instead:
|
||||
|
@ -386,14 +401,20 @@ error[E0382]: use of moved value: `v`
|
|||
```
|
||||
|
||||
Rust’s ownership rules have saved us again! We got an error from the code in
|
||||
Listing 16-3 because Rust was being conservative and only borrowing `v` for the
|
||||
[Listing 16-3][Listing-16-3] because Rust was being conservative and only borrowing `v` for the
|
||||
thread, which meant the main thread could theoretically invalidate the spawned
|
||||
thread’s reference. By telling Rust to move ownership of `v` to the spawned
|
||||
thread, we’re guaranteeing Rust that the main thread won’t use `v` anymore. If
|
||||
we change Listing 16-4 in the same way, we’re then violating the ownership
|
||||
we change [Listing 16-4][Listing-16-4] in the same way, we’re then violating the ownership
|
||||
rules when we try to use `v` in the main thread. The `move` keyword overrides
|
||||
Rust’s conservative default of borrowing; it doesn’t let us violate the
|
||||
ownership rules.
|
||||
|
||||
With a basic understanding of threads and the thread API, let’s look at what we
|
||||
can *do* with threads.
|
||||
|
||||
[Listing-16-1]: ch16-01-threads.html#Listing-16-1
|
||||
[Listing-16-2]: ch16-01-threads.html#Listing-16-2
|
||||
[Listing-16-3]: ch16-01-threads.html#Listing-16-3
|
||||
[Listing-16-4]: ch16-01-threads.html#Listing-16-4
|
||||
[Listing-16-5]: ch16-01-threads.html#Listing-16-5
|
||||
|
|
|
@ -29,12 +29,15 @@ use channels to implement a chat system or a system where many threads perform
|
|||
parts of a calculation and send the parts to one thread that aggregates the
|
||||
results.
|
||||
|
||||
First, in Listing 16-6, we’ll create a channel but not do anything with it.
|
||||
First, in [Listing 16-6][Listing-16-6], we’ll create a channel but not do anything with it.
|
||||
Note that this won’t compile yet because Rust can’t tell what type of values we
|
||||
want to send over the channel.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-6]: #Listing-16-6
|
||||
<a name="Listing-16-6"></a>
|
||||
|
||||
```rust
|
||||
use std::sync::mpsc;
|
||||
|
||||
|
@ -69,11 +72,14 @@ extract the pieces of the tuple returned by `mpsc::channel`.
|
|||
|
||||
Let’s move the transmitting end into a spawned thread and have it send one
|
||||
string so the spawned thread is communicating with the main thread, as shown in
|
||||
Listing 16-7. This is like putting a rubber duck in the river upstream or
|
||||
[Listing 16-7][Listing-16-7]. This is like putting a rubber duck in the river upstream or
|
||||
sending a chat message from one thread to another.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-7]: #Listing-16-7
|
||||
<a name="Listing-16-7"></a>
|
||||
|
||||
```rust
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
|
@ -103,12 +109,15 @@ will return an error. In this example, we’re calling `unwrap` to panic in case
|
|||
of an error. But in a real application, we would handle it properly: return to
|
||||
Chapter 9 to review strategies for proper error handling.
|
||||
|
||||
In Listing 16-8, we’ll get the value from the receiving end of the channel in
|
||||
In [Listing 16-8][Listing-16-8], we’ll get the value from the receiving end of the channel in
|
||||
the main thread. This is like retrieving the rubber duck from the water at the
|
||||
end of the river or like getting a chat message.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-8]: #Listing-16-8
|
||||
<a name="Listing-16-8"></a>
|
||||
|
||||
```rust
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
|
@ -148,7 +157,7 @@ We’ve used `recv` in this example for simplicity; we don’t have any other wo
|
|||
for the main thread to do other than wait for messages, so blocking the main
|
||||
thread is appropriate.
|
||||
|
||||
When we run the code in Listing 16-8, we’ll see the value printed from the main
|
||||
When we run the code in [Listing 16-8][Listing-16-8], we’ll see the value printed from the main
|
||||
thread:
|
||||
|
||||
```text
|
||||
|
@ -164,11 +173,14 @@ write safe, concurrent code. Preventing errors in concurrent programming is the
|
|||
advantage of thinking about ownership throughout your Rust programs. Let’s do
|
||||
an experiment to show how channels and ownership work together to prevent
|
||||
problems: we’ll try to use a `val` value in the spawned thread *after* we’ve
|
||||
sent it down the channel. Try compiling the code in Listing 16-9 to see why
|
||||
sent it down the channel. Try compiling the code in [Listing 16-9][Listing-16-9] to see why
|
||||
this code isn’t allowed:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-9]: #Listing-16-9
|
||||
<a name="Listing-16-9"></a>
|
||||
|
||||
```rust,ignore
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
|
@ -195,7 +207,7 @@ Allowing this would be a bad idea: once the value has been sent to another
|
|||
thread, that thread could modify or drop it before we try to use the value
|
||||
again. Potentially, the other thread’s modifications could cause errors or
|
||||
unexpected results due to inconsistent or nonexistent data. However, Rust gives
|
||||
us an error if we try to compile the code in Listing 16-9:
|
||||
us an error if we try to compile the code in [Listing 16-9][Listing-16-9]:
|
||||
|
||||
```text
|
||||
error[E0382]: use of moved value: `val`
|
||||
|
@ -217,14 +229,17 @@ after sending it; the ownership system checks that everything is okay.
|
|||
|
||||
### Sending Multiple Values and Seeing the Receiver Waiting
|
||||
|
||||
The code in Listing 16-8 compiled and ran, but it didn’t clearly show us that
|
||||
two separate threads were talking to each other over the channel. In Listing
|
||||
16-10 we’ve made some modifications that will prove the code in Listing 16-8 is
|
||||
The code in [Listing 16-8][Listing-16-8] compiled and ran, but it didn’t clearly show us that
|
||||
two separate threads were talking to each other over the channel. In [Listing 16-10][Listing-16-10]
|
||||
we’ve made some modifications that will prove the code in [Listing 16-8][Listing-16-8] is
|
||||
running concurrently: the spawned thread will now send multiple messages and
|
||||
pause for a second between each message.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-10]: #Listing-16-10
|
||||
<a name="Listing-16-10"></a>
|
||||
|
||||
```rust
|
||||
use std::thread;
|
||||
use std::sync::mpsc;
|
||||
|
@ -265,7 +280,7 @@ In the main thread, we’re not calling the `recv` function explicitly anymore:
|
|||
instead, we’re treating `rx` as an iterator. For each value received, we’re
|
||||
printing it. When the channel is closed, iteration will end.
|
||||
|
||||
When running the code in Listing 16-10, you should see the following output
|
||||
When running the code in [Listing 16-10][Listing-16-10], you should see the following output
|
||||
with a 1-second pause in between each line:
|
||||
|
||||
```text
|
||||
|
@ -282,12 +297,15 @@ the spawned thread.
|
|||
### Creating Multiple Producers by Cloning the Transmitter
|
||||
|
||||
Earlier we mentioned that `mpsc` was an acronym for *multiple producer,
|
||||
single consumer*. Let’s put `mpsc` to use and expand the code in Listing 16-10
|
||||
single consumer*. Let’s put `mpsc` to use and expand the code in [Listing 16-10][Listing-16-10]
|
||||
to create multiple threads that all send values to the same receiver. We can do
|
||||
so by cloning the transmitting half of the channel, as shown in Listing 16-11:
|
||||
so by cloning the transmitting half of the channel, as shown in [Listing 16-11][Listing-16-11]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-11]: #Listing-16-11
|
||||
<a name="Listing-16-11"></a>
|
||||
|
||||
```rust
|
||||
# use std::thread;
|
||||
# use std::sync::mpsc;
|
||||
|
@ -364,3 +382,10 @@ will be more nondeterministic and create different output each time.
|
|||
|
||||
Now that we’ve looked at how channels work, let’s look at a different method of
|
||||
concurrency.
|
||||
|
||||
[Listing-16-6]: ch16-02-message-passing.html#Listing-16-6
|
||||
[Listing-16-7]: ch16-02-message-passing.html#Listing-16-7
|
||||
[Listing-16-8]: ch16-02-message-passing.html#Listing-16-8
|
||||
[Listing-16-9]: ch16-02-message-passing.html#Listing-16-9
|
||||
[Listing-16-10]: ch16-02-message-passing.html#Listing-16-10
|
||||
[Listing-16-11]: ch16-02-message-passing.html#Listing-16-11
|
||||
|
|
|
@ -49,10 +49,13 @@ system and ownership rules, you can’t get locking and unlocking wrong.
|
|||
#### The API of `Mutex<T>`
|
||||
|
||||
As an example of how to use a mutex, let’s start by using a mutex in a
|
||||
single-threaded context, as shown in Listing 16-12:
|
||||
single-threaded context, as shown in [Listing 16-12][Listing-16-12]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-12]: #Listing-16-12
|
||||
<a name="Listing-16-12"></a>
|
||||
|
||||
```rust
|
||||
use std::sync::Mutex;
|
||||
|
||||
|
@ -90,8 +93,8 @@ As you might suspect, `Mutex<T>` is a smart pointer. More accurately, the call
|
|||
to `lock` *returns* a smart pointer called `MutexGuard`. This smart pointer
|
||||
implements `Deref` to point at our inner data; the smart pointer also has a
|
||||
`Drop` implementation that releases the lock automatically when a `MutexGuard`
|
||||
goes out of scope, which happens at the end of the inner scope in Listing
|
||||
16-12. As a result, we don’t risk forgetting to release the lock and blocking
|
||||
goes out of scope, which happens at the end of the inner scope in [Listing 16-12][Listing-16-12].
|
||||
As a result, we don’t risk forgetting to release the lock and blocking
|
||||
the mutex from being used by other threads because the lock release happens
|
||||
automatically.
|
||||
|
||||
|
@ -104,11 +107,14 @@ Now, let’s try to share a value between multiple threads using `Mutex<T>`.
|
|||
We’ll spin up 10 threads and have them each increment a counter value by 1, so
|
||||
the counter goes from 0 to 10. Note that the next few examples will have
|
||||
compiler errors, and we’ll use those errors to learn more about using
|
||||
`Mutex<T>` and how Rust helps us use it correctly. Listing 16-13 has our
|
||||
`Mutex<T>` and how Rust helps us use it correctly. [Listing 16-13][Listing-16-13] has our
|
||||
starting example:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-13]: #Listing-16-13
|
||||
<a name="Listing-16-13"></a>
|
||||
|
||||
```rust,ignore
|
||||
use std::sync::Mutex;
|
||||
use std::thread;
|
||||
|
@ -138,15 +144,15 @@ fn main() {
|
|||
guarded by a `Mutex<T>`</span>
|
||||
|
||||
We create a `counter` variable to hold an `i32` inside a `Mutex<T>`, as we
|
||||
did in Listing 16-12. Next, we create 10 threads by iterating over a range
|
||||
did in [Listing 16-12][Listing-16-12]. Next, we create 10 threads by iterating over a range
|
||||
of numbers. We use `thread::spawn` and give all the threads the same closure,
|
||||
one that moves the counter into the thread, acquires a lock on the `Mutex<T>`
|
||||
by calling the `lock` method, and then adds 1 to the value in the mutex. When a
|
||||
thread finishes running its closure, `num` will go out of scope and release the
|
||||
lock so another thread can acquire it.
|
||||
|
||||
In the main thread, we collect all the join handles. Then, as we did in Listing
|
||||
16-2, we call `join` on each handle to make sure all the threads finish. At
|
||||
In the main thread, we collect all the join handles. Then, as we did in [Listing 16-2][Listing-16-2],
|
||||
we call `join` on each handle to make sure all the threads finish. At
|
||||
that point, the main thread will acquire the lock and print the result of this
|
||||
program.
|
||||
|
||||
|
@ -185,7 +191,7 @@ but it’s not allowed!
|
|||
|
||||
Let’s figure this out by simplifying the program. Instead of making 10 threads
|
||||
in a `for` loop, let’s just make two threads without a loop and see what
|
||||
happens. Replace the first `for` loop in Listing 16-13 with this code instead:
|
||||
happens. Replace the first `for` loop in [Listing 16-13][Listing-16-13] with this code instead:
|
||||
|
||||
```rust,ignore
|
||||
use std::sync::Mutex;
|
||||
|
@ -262,13 +268,16 @@ method we discussed in Chapter 15.
|
|||
|
||||
In Chapter 15, we gave a value multiple owners by using the smart pointer
|
||||
`Rc<T>` to create a reference counted value. Let’s do the same here and see
|
||||
what happens. We’ll wrap the `Mutex<T>` in `Rc<T>` in Listing 16-14 and clone
|
||||
what happens. We’ll wrap the `Mutex<T>` in `Rc<T>` in [Listing 16-14][Listing-16-14] and clone
|
||||
the `Rc<T>` before moving ownership to the thread. Now that we’ve seen the
|
||||
errors, we’ll also switch back to using the `for` loop, and we’ll keep the
|
||||
`move` keyword with the closure.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-14]: #Listing-16-14
|
||||
<a name="Listing-16-14"></a>
|
||||
|
||||
```rust,ignore
|
||||
use std::rc::Rc;
|
||||
use std::sync::Mutex;
|
||||
|
@ -356,10 +365,13 @@ guarantees atomics provide.
|
|||
|
||||
Let’s return to our example: `Arc<T>` and `Rc<T>` have the same API, so we fix
|
||||
our program by changing the `use` line, the call to `new`, and the call to
|
||||
`clone`. The code in Listing 16-15 will finally compile and run:
|
||||
`clone`. The code in [Listing 16-15][Listing-16-15] will finally compile and run:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-16-15]: #Listing-16-15
|
||||
<a name="Listing-16-15"></a>
|
||||
|
||||
```rust
|
||||
use std::sync::{Mutex, Arc};
|
||||
use std::thread;
|
||||
|
@ -424,3 +436,9 @@ useful information.
|
|||
|
||||
We’ll round out this chapter by talking about the `Send` and `Sync` traits and
|
||||
how we can use them with custom types.
|
||||
|
||||
[Listing-16-2]: ch16-01-threads.html#Listing-16-2
|
||||
[Listing-16-12]: ch16-03-shared-state.html#Listing-16-12
|
||||
[Listing-16-13]: ch16-03-shared-state.html#Listing-16-13
|
||||
[Listing-16-14]: ch16-03-shared-state.html#Listing-16-14
|
||||
[Listing-16-15]: ch16-03-shared-state.html#Listing-16-15
|
||||
|
|
|
@ -21,7 +21,7 @@ where you don’t want to pay the thread-safe performance penalty.
|
|||
|
||||
Therefore, Rust’s type system and trait bounds ensure that you can never
|
||||
accidentally send an `Rc<T>` value across threads unsafely. When we tried to do
|
||||
this in Listing 16-14, we got the error `the trait Send is not implemented for
|
||||
this in [Listing 16-14][Listing-16-14], we got the error `the trait Send is not implemented for
|
||||
Rc<Mutex<i32>>`. When we switched to `Arc<T>`, which is `Send`, the code
|
||||
compiled.
|
||||
|
||||
|
@ -85,3 +85,5 @@ go forth and make your programs concurrent, fearlessly!
|
|||
Next, we’ll talk about idiomatic ways to model problems and structure solutions
|
||||
as your Rust programs get bigger. In addition, we’ll discuss how Rust’s idioms
|
||||
relate to those you might be familiar with from object-oriented programming.
|
||||
|
||||
[Listing-16-14]: ch16-03-shared-state.html#Listing-16-14
|
||||
|
|
|
@ -41,11 +41,14 @@ can define a struct `AveragedCollection` that has a field containing a vector
|
|||
of `i32` values. The struct can also have a field that contains the average of
|
||||
the values in the vector, meaning the average doesn’t have to be computed
|
||||
on demand whenever anyone needs it. In other words, `AveragedCollection` will
|
||||
cache the calculated average for us. Listing 17-1 has the definition of the
|
||||
cache the calculated average for us. [Listing 17-1][Listing-17-1] has the definition of the
|
||||
`AveragedCollection` struct:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-1]: #Listing-17-1
|
||||
<a name="Listing-17-1"></a>
|
||||
|
||||
```rust
|
||||
pub struct AveragedCollection {
|
||||
list: Vec<i32>,
|
||||
|
@ -61,10 +64,13 @@ The struct is marked `pub` so that other code can use it, but the fields within
|
|||
the struct remain private. This is important in this case because we want to
|
||||
ensure that whenever a value is added or removed from the list, the average is
|
||||
also updated. We do this by implementing `add`, `remove`, and `average` methods
|
||||
on the struct, as shown in Listing 17-2:
|
||||
on the struct, as shown in [Listing 17-2][Listing-17-2]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-2]: #Listing-17-2
|
||||
<a name="Listing-17-2"></a>
|
||||
|
||||
```rust
|
||||
# pub struct AveragedCollection {
|
||||
# list: Vec<i32>,
|
||||
|
@ -142,7 +148,7 @@ depending on your reason for reaching for inheritance in the first place.
|
|||
You choose inheritance for two main reasons. One is for reuse of code: you can
|
||||
implement particular behavior for one type, and inheritance enables you to
|
||||
reuse that implementation for a different type. You can share Rust code using
|
||||
default trait method implementations instead, which you saw in Listing 10-14
|
||||
default trait method implementations instead, which you saw in [Listing 10-14][Listing-10-14]
|
||||
when we added a default implementation of the `summarize` method on the
|
||||
`Summary` trait. Any type implementing the `Summary` trait would have the
|
||||
`summarize` method available on it without any further code. This is similar to
|
||||
|
@ -179,3 +185,7 @@ design.
|
|||
|
||||
For these reasons, Rust takes a different approach, using trait objects instead
|
||||
of inheritance. Let’s look at how trait objects enable polymorphism in Rust.
|
||||
|
||||
[Listing-17-1]: ch17-01-what-is-oo.html#Listing-17-1
|
||||
[Listing-17-2]: ch17-01-what-is-oo.html#Listing-17-2
|
||||
[Listing-10-14]: ch10-02-traits.html#Listing-10-14
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
## Using Trait Objects that Allow for Values of Different Types
|
||||
|
||||
In Chapter 8, we mentioned that one limitation of vectors is that they can
|
||||
store elements of only one type. We created a workaround in Listing 8-10 where
|
||||
store elements of only one type. We created a workaround in [Listing 8-10][Listing-8-10] where
|
||||
we defined a `SpreadsheetCell` enum that had variants to hold integers, floats,
|
||||
and text. This meant we could store different types of data in each cell and
|
||||
still have a vector that represented a row of cells. This is a perfectly good
|
||||
|
@ -63,11 +63,14 @@ a trait object. Trait objects aren’t as generally useful as objects in other
|
|||
languages: their specific purpose is to allow abstraction across common
|
||||
behavior.
|
||||
|
||||
Listing 17-3 shows how to define a trait named `Draw` with one method named
|
||||
[Listing 17-3][Listing-17-3] shows how to define a trait named `Draw` with one method named
|
||||
`draw`:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-3]: #Listing-17-3
|
||||
<a name="Listing-17-3"></a>
|
||||
|
||||
```rust
|
||||
pub trait Draw {
|
||||
fn draw(&self);
|
||||
|
@ -77,13 +80,16 @@ pub trait Draw {
|
|||
<span class="caption">Listing 17-3: Definition of the `Draw` trait</span>
|
||||
|
||||
This syntax should look familiar from our discussions on how to define traits
|
||||
in Chapter 10. Next comes some new syntax: Listing 17-4 defines a struct named
|
||||
in Chapter 10. Next comes some new syntax: [Listing 17-4][Listing-17-4] defines a struct named
|
||||
`Screen` that holds a vector named `components`. This vector is of type
|
||||
`Box<Draw>`, which is a trait object; it’s a stand-in for any type inside a
|
||||
`Box` that implements the `Draw` trait.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-4]: #Listing-17-4
|
||||
<a name="Listing-17-4"></a>
|
||||
|
||||
```rust
|
||||
# pub trait Draw {
|
||||
# fn draw(&self);
|
||||
|
@ -99,10 +105,13 @@ pub struct Screen {
|
|||
trait</span>
|
||||
|
||||
On the `Screen` struct, we’ll define a method named `run` that will call the
|
||||
`draw` method on each of its `components`, as shown in Listing 17-5:
|
||||
`draw` method on each of its `components`, as shown in [Listing 17-5][Listing-17-5]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-5]: #Listing-17-5
|
||||
<a name="Listing-17-5"></a>
|
||||
|
||||
```rust
|
||||
# pub trait Draw {
|
||||
# fn draw(&self);
|
||||
|
@ -129,10 +138,13 @@ parameter with trait bounds. A generic type parameter can only be substituted
|
|||
with one concrete type at a time, whereas trait objects allow for multiple
|
||||
concrete types to fill in for the trait object at runtime. For example, we
|
||||
could have defined the `Screen` struct using a generic type and a trait bound
|
||||
as in Listing 17-6:
|
||||
as in [Listing 17-6][Listing-17-6]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-6]: #Listing-17-6
|
||||
<a name="Listing-17-6"></a>
|
||||
|
||||
```rust
|
||||
# pub trait Draw {
|
||||
# fn draw(&self);
|
||||
|
@ -171,10 +183,13 @@ Now we’ll add some types that implement the `Draw` trait. We’ll provide the
|
|||
`Button` type. Again, actually implementing a GUI library is beyond the scope
|
||||
of this book, so the `draw` method won’t have any useful implementation in its
|
||||
body. To imagine what the implementation might look like, a `Button` struct
|
||||
might have fields for `width`, `height`, and `label`, as shown in Listing 17-7:
|
||||
might have fields for `width`, `height`, and `label`, as shown in [Listing 17-7][Listing-17-7]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-7]: #Listing-17-7
|
||||
<a name="Listing-17-7"></a>
|
||||
|
||||
```rust
|
||||
# pub trait Draw {
|
||||
# fn draw(&self);
|
||||
|
@ -208,10 +223,13 @@ methods won’t apply to types like `TextField`.
|
|||
|
||||
If someone using our library decides to implement a `SelectBox` struct that has
|
||||
`width`, `height`, and `options` fields, they implement the `Draw` trait on the
|
||||
`SelectBox` type as well, as shown in Listing 17-8:
|
||||
`SelectBox` type as well, as shown in [Listing 17-8][Listing-17-8]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-17-8]: #Listing-17-8
|
||||
<a name="Listing-17-8"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate gui;
|
||||
use gui::Draw;
|
||||
|
@ -236,10 +254,13 @@ Our library’s user can now write their `main` function to create a `Screen`
|
|||
instance. To the `Screen` instance, they can add a `SelectBox` and a `Button`
|
||||
by putting each in a `Box<T>` to become a trait object. They can then call the
|
||||
`run` method on the `Screen` instance, which will call `draw` on each of the
|
||||
components. Listing 17-9 shows this implementation:
|
||||
components. [Listing 17-9][Listing-17-9] shows this implementation:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-17-9]: #Listing-17-9
|
||||
<a name="Listing-17-9"></a>
|
||||
|
||||
```rust,ignore
|
||||
use gui::{Screen, Button};
|
||||
|
||||
|
@ -278,8 +299,8 @@ means it implements the `draw` method.
|
|||
This concept—of being concerned only with the messages a value responds to
|
||||
rather than the value’s concrete type—is similar to the concept *duck typing*
|
||||
in dynamically typed languages: if it walks like a duck and quacks like a duck,
|
||||
then it must be a duck! In the implementation of `run` on `Screen` in Listing
|
||||
17-5, `run` doesn’t need to know what the concrete type of each component is.
|
||||
then it must be a duck! In the implementation of `run` on `Screen` in [Listing 17-5][Listing-17-5],
|
||||
`run` doesn’t need to know what the concrete type of each component is.
|
||||
It doesn’t check whether a component is an instance of a `Button` or a
|
||||
`SelectBox`, it just calls the `draw` method on the component. By specifying
|
||||
`Box<Draw>` as the type of the values in the `components` vector, we’ve defined
|
||||
|
@ -291,11 +312,14 @@ value implements a particular method at runtime or worry about getting errors
|
|||
if a value doesn’t implement a method but we call it anyway. Rust won’t compile
|
||||
our code if the values don’t implement the traits that the trait objects need.
|
||||
|
||||
For example, Listing 17-10 shows what happens if we try to create a `Screen`
|
||||
For example, [Listing 17-10][Listing-17-10] shows what happens if we try to create a `Screen`
|
||||
with a `String` as a component:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-17-10]: #Listing-17-10
|
||||
<a name="Listing-17-10"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate gui;
|
||||
use gui::Screen;
|
||||
|
@ -352,7 +376,7 @@ which method to call. There is a runtime cost when this lookup happens that
|
|||
doesn’t occur with static dispatch. Dynamic dispatch also prevents the compiler
|
||||
from choosing to inline a method’s code, which in turn prevents some
|
||||
optimizations. However, we did get extra flexibility in the code that we wrote
|
||||
in Listing 17-5 and were able to support in Listing 17-9, so it’s a trade-off
|
||||
in [Listing 17-5][Listing-17-5] and were able to support in [Listing 17-9][Listing-17-9], so it’s a trade-off
|
||||
to consider.
|
||||
|
||||
### Object Safety Is Required for Trait Objects
|
||||
|
@ -394,7 +418,7 @@ stand in for `Self`, because that’s the return type.
|
|||
|
||||
The compiler will indicate when you’re trying to do something that violates the
|
||||
rules of object safety in regard to trait objects. For example, let’s say we
|
||||
tried to implement the `Screen` struct in Listing 17-4 to hold types that
|
||||
tried to implement the `Screen` struct in [Listing 17-4][Listing-17-4] to hold types that
|
||||
implement the `Clone` trait instead of the `Draw` trait, like this:
|
||||
|
||||
```rust,ignore
|
||||
|
@ -420,3 +444,13 @@ This error means you can’t use this trait as a trait object in this way. If
|
|||
you’re interested in more details on object safety, see [Rust RFC 255].
|
||||
|
||||
[Rust RFC 255]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md
|
||||
|
||||
[Listing-17-3]: ch17-02-trait-objects.html#Listing-17-3
|
||||
[Listing-17-4]: ch17-02-trait-objects.html#Listing-17-4
|
||||
[Listing-17-5]: ch17-02-trait-objects.html#Listing-17-5
|
||||
[Listing-17-6]: ch17-02-trait-objects.html#Listing-17-6
|
||||
[Listing-17-7]: ch17-02-trait-objects.html#Listing-17-7
|
||||
[Listing-17-8]: ch17-02-trait-objects.html#Listing-17-8
|
||||
[Listing-17-9]: ch17-02-trait-objects.html#Listing-17-9
|
||||
[Listing-17-10]: ch17-02-trait-objects.html#Listing-17-10
|
||||
[Listing-8-10]: ch08-01-vectors.html#Listing-8-10
|
||||
|
|
|
@ -28,12 +28,15 @@ Any other changes attempted on a post should have no effect. For example, if we
|
|||
try to approve a draft blog post before we’ve requested a review, the post
|
||||
should remain an unpublished draft.
|
||||
|
||||
Listing 17-11 shows this workflow in code form: this is an example usage of the
|
||||
[Listing 17-11][Listing-17-11] shows this workflow in code form: this is an example usage of the
|
||||
API we’ll implement in a library crate named `blog`. This won’t compile yet
|
||||
because we haven’t implemented the `blog` crate yet.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-17-11]: #Listing-17-11
|
||||
<a name="Listing-17-11"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate blog;
|
||||
use blog::Post;
|
||||
|
@ -82,13 +85,16 @@ make a mistake with the states, like publishing a post before it’s reviewed.
|
|||
Let’s get started on the implementation of the library! We know we need a
|
||||
public `Post` struct that holds some content, so we’ll start with the
|
||||
definition of the struct and an associated public `new` function to create an
|
||||
instance of `Post`, as shown in Listing 17-12. We’ll also make a private
|
||||
instance of `Post`, as shown in [Listing 17-12][Listing-17-12]. We’ll also make a private
|
||||
`State` trait. Then `Post` will hold a trait object of `Box<State>` inside an
|
||||
`Option` in a private field named `state`. You’ll see why the `Option` is
|
||||
necessary in a bit.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-12]: #Listing-17-12
|
||||
<a name="Listing-17-12"></a>
|
||||
|
||||
```rust
|
||||
pub struct Post {
|
||||
state: Option<Box<State>>,
|
||||
|
@ -129,16 +135,19 @@ create a `Post` in any other state! In the `Post::new` function, we set the
|
|||
|
||||
### Storing the Text of the Post Content
|
||||
|
||||
Listing 17-11 showed that we want to be able to call a method named
|
||||
[Listing 17-11][Listing-17-11] showed that we want to be able to call a method named
|
||||
`add_text` and pass it a `&str` that is then added to the text content of the
|
||||
blog post. We implement this as a method rather than exposing the `content`
|
||||
field as `pub`. This means we can implement a method later that will control
|
||||
how the `content` field’s data is read. The `add_text` method is pretty
|
||||
straightforward, so let’s add the implementation in Listing 17-13 to the `impl
|
||||
straightforward, so let’s add the implementation in [Listing 17-13][Listing-17-13] to the `impl
|
||||
Post` block:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-13]: #Listing-17-13
|
||||
<a name="Listing-17-13"></a>
|
||||
|
||||
```rust
|
||||
# pub struct Post {
|
||||
# content: String,
|
||||
|
@ -167,15 +176,18 @@ support.
|
|||
|
||||
Even after we’ve called `add_text` and added some content to our post, we still
|
||||
want the `content` method to return an empty string slice because the post is
|
||||
still in the draft state, as shown on line 8 of Listing 17-11. For now, let’s
|
||||
still in the draft state, as shown on line 8 of [Listing 17-11][Listing-17-11]. For now, let’s
|
||||
implement the `content` method with the simplest thing that will fulfill this
|
||||
requirement: always returning an empty string slice. We’ll change this later
|
||||
once we implement the ability to change a post’s state so it can be published.
|
||||
So far, posts can only be in the draft state, so the post content should always
|
||||
be empty. Listing 17-14 shows this placeholder implementation:
|
||||
be empty. [Listing 17-14][Listing-17-14] shows this placeholder implementation:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-14]: #Listing-17-14
|
||||
<a name="Listing-17-14"></a>
|
||||
|
||||
```rust
|
||||
# pub struct Post {
|
||||
# content: String,
|
||||
|
@ -192,16 +204,19 @@ impl Post {
|
|||
<span class="caption">Listing 17-14: Adding a placeholder implementation for
|
||||
the `content` method on `Post` that always returns an empty string slice</span>
|
||||
|
||||
With this added `content` method, everything in Listing 17-11 up to line 8
|
||||
With this added `content` method, everything in [Listing 17-11][Listing-17-11] up to line 8
|
||||
works as intended.
|
||||
|
||||
### Requesting a Review of the Post Changes Its State
|
||||
|
||||
Next, we need to add functionality to request a review of a post, which should
|
||||
change its state from `Draft` to `PendingReview`. Listing 17-15 shows this code:
|
||||
change its state from `Draft` to `PendingReview`. [Listing 17-15][Listing-17-15] shows this code:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-15]: #Listing-17-15
|
||||
<a name="Listing-17-15"></a>
|
||||
|
||||
```rust
|
||||
# pub struct Post {
|
||||
# state: Option<Box<State>>,
|
||||
|
@ -281,16 +296,19 @@ state is responsible for its own rules.
|
|||
We’ll leave the `content` method on `Post` as is, returning an empty string
|
||||
slice. We can now have a `Post` in the `PendingReview` state as well as in the
|
||||
`Draft` state, but we want the same behavior in the `PendingReview` state.
|
||||
Listing 17-11 now works up to line 11!
|
||||
[Listing 17-11][Listing-17-11] now works up to line 11!
|
||||
|
||||
### Adding the `approve` Method that Changes the Behavior of `content`
|
||||
|
||||
The `approve` method will be similar to the `request_review` method: it will
|
||||
set `state` to the value that the current state says it should have when that
|
||||
state is approved, as shown in Listing 17-16:
|
||||
state is approved, as shown in [Listing 17-16][Listing-17-16]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-16]: #Listing-17-16
|
||||
<a name="Listing-17-16"></a>
|
||||
|
||||
```rust
|
||||
# pub struct Post {
|
||||
# state: Option<Box<State>>,
|
||||
|
@ -365,10 +383,13 @@ the post should stay in the `Published` state in those cases.
|
|||
|
||||
Now we need to update the `content` method on `Post`: if the state is
|
||||
`Published`, we want to return the value in the post’s `content` field;
|
||||
otherwise, we want to return an empty string slice, as shown in Listing 17-17:
|
||||
otherwise, we want to return an empty string slice, as shown in [Listing 17-17][Listing-17-17]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-17]: #Listing-17-17
|
||||
<a name="Listing-17-17"></a>
|
||||
|
||||
```rust
|
||||
# trait State {
|
||||
# fn content<'a>(&self, post: &'a Post) -> &'a str;
|
||||
|
@ -413,10 +434,13 @@ take effect on the `&` and the `Box` so the `content` method will ultimately be
|
|||
called on the type that implements the `State` trait. That means we need to add
|
||||
`content` to the `State` trait definition, and that is where we’ll put the
|
||||
logic for what content to return depending on which state we have, as shown in
|
||||
Listing 17-18:
|
||||
[Listing 17-18][Listing-17-18]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-18]: #Listing-17-18
|
||||
<a name="Listing-17-18"></a>
|
||||
|
||||
```rust
|
||||
# pub struct Post {
|
||||
# content: String
|
||||
|
@ -452,7 +476,7 @@ Chapter 10. We’re taking a reference to a `post` as an argument and returning
|
|||
reference to part of that `post`, so the lifetime of the returned reference is
|
||||
related to the lifetime of the `post` argument.
|
||||
|
||||
And we’re done—all of Listing 17-11 now works! We’ve implemented the state
|
||||
And we’re done—all of [Listing 17-11][Listing-17-11] now works! We’ve implemented the state
|
||||
pattern with the rules of the blog post workflow. The logic related to the
|
||||
rules lives in the state objects rather than being scattered throughout `Post`.
|
||||
|
||||
|
@ -523,7 +547,7 @@ outside code has no knowledge of them, we’ll encode the states into different
|
|||
types. Consequently, Rust’s type checking system will prevent attempts to use
|
||||
draft posts where only published posts are allowed by issuing a compiler error.
|
||||
|
||||
Let’s consider the first part of `main` in Listing 17-11:
|
||||
Let’s consider the first part of `main` in [Listing 17-11][Listing-17-11]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
|
@ -543,11 +567,14 @@ draft posts don’t have the `content` method at all. That way, if we try to get
|
|||
a draft post’s content, we’ll get a compiler error telling us the method
|
||||
doesn’t exist. As a result, it will be impossible for us to accidentally
|
||||
display draft post content in production, because that code won’t even compile.
|
||||
Listing 17-19 shows the definition of a `Post` struct and a `DraftPost` struct,
|
||||
[Listing 17-19][Listing-17-19] shows the definition of a `Post` struct and a `DraftPost` struct,
|
||||
as well as methods on each:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-19]: #Listing-17-19
|
||||
<a name="Listing-17-19"></a>
|
||||
|
||||
```rust
|
||||
pub struct Post {
|
||||
content: String,
|
||||
|
@ -604,10 +631,13 @@ pending review state should still not display any content. Let’s implement
|
|||
these constraints by adding another struct, `PendingReviewPost`, defining the
|
||||
`request_review` method on `DraftPost` to return a `PendingReviewPost`, and
|
||||
defining an `approve` method on `PendingReviewPost` to return a `Post`, as
|
||||
shown in Listing 17-20:
|
||||
shown in [Listing 17-20][Listing-17-20]:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-17-20]: #Listing-17-20
|
||||
<a name="Listing-17-20"></a>
|
||||
|
||||
```rust
|
||||
# pub struct Post {
|
||||
# content: String,
|
||||
|
@ -662,10 +692,13 @@ called on, so we need to add more `let post =` shadowing assignments to save
|
|||
the returned instances. We also can’t have the assertions about the draft and
|
||||
pending review post’s contents be empty strings, nor do we need them: we can’t
|
||||
compile code that tries to use the content of posts in those states any longer.
|
||||
The updated code in `main` is shown in Listing 17-21:
|
||||
The updated code in `main` is shown in [Listing 17-21][Listing-17-21]:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-17-21]: #Listing-17-21
|
||||
<a name="Listing-17-21"></a>
|
||||
|
||||
```rust,ignore
|
||||
extern crate blog;
|
||||
use blog::Post;
|
||||
|
@ -695,7 +728,7 @@ compile time! This ensures that certain bugs, such as display of the content of
|
|||
an unpublished post, will be discovered before they make it to production.
|
||||
|
||||
Try the tasks suggested for additional requirements that we mentioned at the
|
||||
start of this section on the `blog` crate as it is after Listing 17-20 to see
|
||||
start of this section on the `blog` crate as it is after [Listing 17-20][Listing-17-20] to see
|
||||
what you think about the design of this version of the code. Note that some of
|
||||
the tasks might be completed already in this design.
|
||||
|
||||
|
@ -723,3 +756,15 @@ option.
|
|||
Next, we’ll look at patterns, which are another of Rust’s features that enable
|
||||
lots of flexibility. We’ve looked at them briefly throughout the book but
|
||||
haven’t seen their full capability yet. Let’s go!
|
||||
|
||||
[Listing-17-11]: ch17-03-oo-design-patterns.html#Listing-17-11
|
||||
[Listing-17-12]: ch17-03-oo-design-patterns.html#Listing-17-12
|
||||
[Listing-17-13]: ch17-03-oo-design-patterns.html#Listing-17-13
|
||||
[Listing-17-14]: ch17-03-oo-design-patterns.html#Listing-17-14
|
||||
[Listing-17-15]: ch17-03-oo-design-patterns.html#Listing-17-15
|
||||
[Listing-17-16]: ch17-03-oo-design-patterns.html#Listing-17-16
|
||||
[Listing-17-17]: ch17-03-oo-design-patterns.html#Listing-17-17
|
||||
[Listing-17-18]: ch17-03-oo-design-patterns.html#Listing-17-18
|
||||
[Listing-17-19]: ch17-03-oo-design-patterns.html#Listing-17-19
|
||||
[Listing-17-20]: ch17-03-oo-design-patterns.html#Listing-17-20
|
||||
[Listing-17-21]: ch17-03-oo-design-patterns.html#Listing-17-21
|
||||
|
|
|
@ -38,19 +38,22 @@ way to write the equivalent of a `match` that only matches one case.
|
|||
Optionally, `if let` can have a corresponding `else` containing code to run if
|
||||
the pattern in the `if let` doesn’t match.
|
||||
|
||||
Listing 18-1 shows that it’s also possible to mix and match `if let`, `else
|
||||
[Listing 18-1][Listing-18-1] shows that it’s also possible to mix and match `if let`, `else
|
||||
if`, and `else if let` expressions. Doing so gives us more flexibility than a
|
||||
`match` expression in which we can express only one value to compare with the
|
||||
patterns. Also, the conditions in a series of `if let`, `else if`, `else if
|
||||
let` arms aren’t required to relate to each other.
|
||||
|
||||
The code in Listing 18-1 shows a series of checks for several conditions that
|
||||
The code in [Listing 18-1][Listing-18-1] shows a series of checks for several conditions that
|
||||
decide what the background color should be. For this example, we’ve created
|
||||
variables with hardcoded values that a real program might receive from user
|
||||
input.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-18-1]: #Listing-18-1
|
||||
<a name="Listing-18-1"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let favorite_color: Option<&str> = None;
|
||||
|
@ -103,9 +106,12 @@ not alert us to the possible logic bug.
|
|||
|
||||
Similar in construction to `if let`, the `while let` conditional loop allows a
|
||||
`while` loop to run for as long as a pattern continues to match. The example in
|
||||
Listing 18-2 shows a `while let` loop that uses a vector as a stack and prints
|
||||
[Listing 18-2][Listing-18-2] shows a `while let` loop that uses a vector as a stack and prints
|
||||
the values in the vector in the opposite order in which they were pushed.
|
||||
|
||||
[Listing-18-2]: #Listing-18-2
|
||||
<a name="Listing-18-2"></a>
|
||||
|
||||
```rust
|
||||
let mut stack = Vec::new();
|
||||
|
||||
|
@ -134,9 +140,12 @@ construction in Rust code, but we haven’t yet discussed the pattern that `for`
|
|||
takes. In a `for` loop, the pattern is the value that directly follows the
|
||||
keyword `for`, so in `for x in y` the `x` is the pattern.
|
||||
|
||||
Listing 18-3 demonstrates how to use a pattern in a `for` loop to destructure,
|
||||
[Listing 18-3][Listing-18-3] demonstrates how to use a pattern in a `for` loop to destructure,
|
||||
or break apart, a tuple as part of the `for` loop.
|
||||
|
||||
[Listing-18-3]: #Listing-18-3
|
||||
<a name="Listing-18-3"></a>
|
||||
|
||||
```rust
|
||||
let v = vec!['a', 'b', 'c'];
|
||||
|
||||
|
@ -148,7 +157,7 @@ for (index, value) in v.iter().enumerate() {
|
|||
<span class="caption">Listing 18-3: Using a pattern in a `for` loop to
|
||||
destructure a tuple</span>
|
||||
|
||||
The code in Listing 18-3 will print the following:
|
||||
The code in [Listing 18-3][Listing-18-3] will print the following:
|
||||
|
||||
```text
|
||||
a is at index 0
|
||||
|
@ -188,8 +197,11 @@ the expression against the pattern and assigns any names it finds. So in the
|
|||
the variable `x`.” Because the name `x` is the whole pattern, this pattern
|
||||
effectively means “bind everything to the variable `x`, whatever the value is.”
|
||||
|
||||
To see the pattern matching aspect of `let` more clearly, consider Listing
|
||||
18-4, which uses a pattern with `let` to destructure a tuple.
|
||||
To see the pattern matching aspect of `let` more clearly, consider [Listing 18-4][Listing-18-4],
|
||||
which uses a pattern with `let` to destructure a tuple.
|
||||
|
||||
[Listing-18-4]: #Listing-18-4
|
||||
<a name="Listing-18-4"></a>
|
||||
|
||||
```rust
|
||||
let (x, y, z) = (1, 2, 3);
|
||||
|
@ -205,9 +217,12 @@ pattern as nesting three individual variable patterns inside it.
|
|||
|
||||
If the number of elements in the pattern doesn’t match the number of elements
|
||||
in the tuple, the overall type won’t match and we’ll get a compiler error. For
|
||||
example, Listing 18-5 shows an attempt to destructure a tuple with three
|
||||
example, [Listing 18-5][Listing-18-5] shows an attempt to destructure a tuple with three
|
||||
elements into two variables, which won’t work.
|
||||
|
||||
[Listing-18-5]: #Listing-18-5
|
||||
<a name="Listing-18-5"></a>
|
||||
|
||||
```rust,ignore
|
||||
let (x, y) = (1, 2, 3);
|
||||
```
|
||||
|
@ -236,10 +251,13 @@ the number of elements in the tuple.
|
|||
|
||||
### Function Parameters
|
||||
|
||||
Function parameters can also be patterns. The code in Listing 18-6, which
|
||||
Function parameters can also be patterns. The code in [Listing 18-6][Listing-18-6], which
|
||||
declares a function named `foo` that takes one parameter named `x` of type
|
||||
`i32`, should by now look familiar.
|
||||
|
||||
[Listing-18-6]: #Listing-18-6
|
||||
<a name="Listing-18-6"></a>
|
||||
|
||||
```rust
|
||||
fn foo(x: i32) {
|
||||
// code goes here
|
||||
|
@ -250,11 +268,14 @@ fn foo(x: i32) {
|
|||
parameters</span>
|
||||
|
||||
The `x` part is a pattern! As we did with `let`, we could match a tuple in a
|
||||
function’s arguments to the pattern. Listing 18-7 splits the values in a tuple
|
||||
function’s arguments to the pattern. [Listing 18-7][Listing-18-7] splits the values in a tuple
|
||||
as we pass it to a function.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-18-7]: #Listing-18-7
|
||||
<a name="Listing-18-7"></a>
|
||||
|
||||
```rust
|
||||
fn print_coordinates(&(x, y): &(i32, i32)) {
|
||||
println!("Current location: ({}, {})", x, y);
|
||||
|
@ -280,3 +301,11 @@ At this point, you’ve seen several ways of using patterns, but patterns don’
|
|||
work the same in every place we can use them. In some places, the patterns must
|
||||
be irrefutable; in other circumstances, they can be refutable. We’ll discuss
|
||||
these two concepts next.
|
||||
|
||||
[Listing-18-1]: ch18-01-all-the-places-for-patterns.html#Listing-18-1
|
||||
[Listing-18-2]: ch18-01-all-the-places-for-patterns.html#Listing-18-2
|
||||
[Listing-18-3]: ch18-01-all-the-places-for-patterns.html#Listing-18-3
|
||||
[Listing-18-4]: ch18-01-all-the-places-for-patterns.html#Listing-18-4
|
||||
[Listing-18-5]: ch18-01-all-the-places-for-patterns.html#Listing-18-5
|
||||
[Listing-18-6]: ch18-01-all-the-places-for-patterns.html#Listing-18-6
|
||||
[Listing-18-7]: ch18-01-all-the-places-for-patterns.html#Listing-18-7
|
||||
|
|
|
@ -22,10 +22,13 @@ those cases, you’ll need to change either the pattern or the construct you’r
|
|||
using the pattern with, depending on the intended behavior of the code.
|
||||
|
||||
Let’s look at an example of what happens when we try to use a refutable pattern
|
||||
where Rust requires an irrefutable pattern and vice versa. Listing 18-8 shows a
|
||||
where Rust requires an irrefutable pattern and vice versa. [Listing 18-8][Listing-18-8] shows a
|
||||
`let` statement, but for the pattern we’ve specified `Some(x)`, a refutable
|
||||
pattern. As you might expect, this code will not compile.
|
||||
|
||||
[Listing-18-8]: #Listing-18-8
|
||||
<a name="Listing-18-8"></a>
|
||||
|
||||
```rust,ignore
|
||||
let Some(x) = some_option_value;
|
||||
```
|
||||
|
@ -54,7 +57,10 @@ To fix the problem where we have a refutable pattern where an irrefutable
|
|||
pattern is needed, we can change the code that uses the pattern: instead of
|
||||
using `let`, we can use `if let`. Then if the pattern doesn’t match, the code
|
||||
will just skip the code in the curly brackets, giving it a way to continue
|
||||
validly. Listing 18-9 shows how to fix the code in Listing 18-8.
|
||||
validly. [Listing 18-9][Listing-18-9] shows how to fix the code in [Listing 18-8][Listing-18-8].
|
||||
|
||||
[Listing-18-9]: #Listing-18-9
|
||||
<a name="Listing-18-9"></a>
|
||||
|
||||
```rust
|
||||
# let some_option_value: Option<i32> = None;
|
||||
|
@ -68,9 +74,12 @@ patterns instead of `let`</span>
|
|||
|
||||
We’ve given the code an out! This code is perfectly valid, although it means we
|
||||
cannot use an irrefutable pattern without receiving an error. If we give `if
|
||||
let` a pattern that will always match, such as `x`, as shown in Listing 18-10,
|
||||
let` a pattern that will always match, such as `x`, as shown in [Listing 18-10][Listing-18-10],
|
||||
it will not compile.
|
||||
|
||||
[Listing-18-10]: #Listing-18-10
|
||||
<a name="Listing-18-10"></a>
|
||||
|
||||
```rust,ignore
|
||||
if let x = 5 {
|
||||
println!("{}", x);
|
||||
|
@ -100,3 +109,7 @@ this syntax isn’t particularly useful and could be replaced with a simpler
|
|||
Now that you know where to use patterns and the difference between refutable
|
||||
and irrefutable patterns, let’s cover all the syntax we can use to create
|
||||
patterns.
|
||||
|
||||
[Listing-18-8]: ch18-02-refutability.html#Listing-18-8
|
||||
[Listing-18-9]: ch18-02-refutability.html#Listing-18-9
|
||||
[Listing-18-10]: ch18-02-refutability.html#Listing-18-10
|
||||
|
|
|
@ -31,7 +31,7 @@ them many times in the book. However, there is a complication when you use
|
|||
named variables in `match` expressions. Because `match` starts a new scope,
|
||||
variables declared as part of a pattern inside the `match` expression will
|
||||
shadow those with the same name outside the `match` construct, as is the case
|
||||
with all variables. In Listing 18-11, we declare a variable named `x` with the
|
||||
with all variables. In [Listing 18-11][Listing-18-11], we declare a variable named `x` with the
|
||||
value `Some(5)` and a variable `y` with the value `10`. We then create a
|
||||
`match` expression on the value `x`. Look at the patterns in the match arms and
|
||||
`println!` at the end, and try to figure out what the code will print before
|
||||
|
@ -39,6 +39,9 @@ running this code or reading further.
|
|||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-18-11]: #Listing-18-11
|
||||
<a name="Listing-18-11"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = Some(5);
|
||||
|
@ -151,11 +154,14 @@ to use different parts of these values. Let’s walk through each value.
|
|||
|
||||
#### Destructuring Structs
|
||||
|
||||
Listing 18-12 shows a `Point` struct with two fields, `x` and `y`, that we can
|
||||
[Listing 18-12][Listing-18-12] shows a `Point` struct with two fields, `x` and `y`, that we can
|
||||
break apart using a pattern with a `let` statement.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-18-12]: #Listing-18-12
|
||||
<a name="Listing-18-12"></a>
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
|
@ -184,12 +190,15 @@ Because having variable names match the fields is common and because writing
|
|||
`let Point { x: x, y: y } = p;` contains a lot of duplication, there is a
|
||||
shorthand for patterns that match struct fields: you only need to list the name
|
||||
of the struct field, and the variables created from the pattern will have the
|
||||
same names. Listing 18-13 shows code that behaves in the same way as the code
|
||||
in Listing 18-12, but the variables created in the `let` pattern are `x` and
|
||||
same names. [Listing 18-13][Listing-18-13] shows code that behaves in the same way as the code
|
||||
in [Listing 18-12][Listing-18-12], but the variables created in the `let` pattern are `x` and
|
||||
`y` instead of `a` and `b`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-18-13]: #Listing-18-13
|
||||
<a name="Listing-18-13"></a>
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
|
@ -217,12 +226,15 @@ rather than creating variables for all the fields. Doing so allows us to test
|
|||
some of the fields for particular values while creating variables to
|
||||
destructure the other fields.
|
||||
|
||||
Listing 18-14 shows a `match` expression that separates `Point` values into
|
||||
[Listing 18-14][Listing-18-14] shows a `match` expression that separates `Point` values into
|
||||
three cases: points that lie directly on the `x` axis (which is true when `y =
|
||||
0`), on the `y` axis (`x = 0`), or neither.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-18-14]: #Listing-18-14
|
||||
<a name="Listing-18-14"></a>
|
||||
|
||||
```rust
|
||||
# struct Point {
|
||||
# x: i32,
|
||||
|
@ -258,14 +270,17 @@ containing a 0, so this code will print `On the y axis at 7`.
|
|||
#### Destructuring Enums
|
||||
|
||||
We’ve destructured enums earlier in this book, for example, when we
|
||||
destructured `Option<i32>` in Listing 6-5 in Chapter 6. One detail we haven’t
|
||||
destructured `Option<i32>` in [Listing 6-5][Listing-6-5] in Chapter 6. One detail we haven’t
|
||||
mentioned explicitly is that the pattern to destructure an enum should
|
||||
correspond to the way the data stored within the enum is defined. As an
|
||||
example, in Listing 18-15 we use the `Message` enum from Listing 6-2 and write
|
||||
example, in [Listing 18-15][Listing-18-15] we use the `Message` enum from [Listing 6-2][Listing-6-2] and write
|
||||
a `match` with patterns that will destructure each inner value.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-18-15]: #Listing-18-15
|
||||
<a name="Listing-18-15"></a>
|
||||
|
||||
```rust
|
||||
enum Message {
|
||||
Quit,
|
||||
|
@ -315,7 +330,7 @@ For struct-like enum variants, such as `Message::Move`, we can use a pattern
|
|||
similar to the pattern we specify to match structs. After the variant name, we
|
||||
place curly brackets and then list the fields with variables so we break apart
|
||||
the pieces to use in the code for this arm. Here we use the shorthand form as
|
||||
we did in Listing 18-13.
|
||||
we did in [Listing 18-13][Listing-18-13].
|
||||
|
||||
For tuple-like enum variants, like `Message::Write` that holds a tuple with one
|
||||
element and `Message::ChangeColor` that holds a tuple with three elements, the
|
||||
|
@ -333,10 +348,13 @@ This technique is especially useful in closures where we have iterators that
|
|||
iterate over references, but we want to use the values in the closure rather
|
||||
than the references.
|
||||
|
||||
The example in Listing 18-16 iterates over references to `Point` instances in a
|
||||
The example in [Listing 18-16][Listing-18-16] iterates over references to `Point` instances in a
|
||||
vector, destructuring the reference and the struct so we can perform
|
||||
calculations on the `x` and `y` values easily.
|
||||
|
||||
[Listing-18-16]: #Listing-18-16
|
||||
<a name="Listing-18-16"></a>
|
||||
|
||||
```rust
|
||||
# struct Point {
|
||||
# x: i32,
|
||||
|
@ -417,10 +435,13 @@ parts of a value. Let’s explore how and why to use each of these patterns.
|
|||
We’ve used the underscore (`_`) as a wildcard pattern that will match any value
|
||||
but not bind to the value. Although the underscore `_` pattern is especially
|
||||
useful as the last arm in a `match` expression, we can use it in any pattern,
|
||||
including function parameters, as shown in Listing 18-17.
|
||||
including function parameters, as shown in [Listing 18-17][Listing-18-17].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-18-17]: #Listing-18-17
|
||||
<a name="Listing-18-17"></a>
|
||||
|
||||
```rust
|
||||
fn foo(_: i32, y: i32) {
|
||||
println!("This code only uses the y parameter: {}", y);
|
||||
|
@ -448,12 +469,15 @@ name instead.
|
|||
|
||||
We can also use `_` inside another pattern to ignore just part of a value, for
|
||||
example, when we want to test for only part of a value but have no use for the
|
||||
other parts in the corresponding code we want to run. Listing 18-18 shows code
|
||||
other parts in the corresponding code we want to run. [Listing 18-18][Listing-18-18] shows code
|
||||
responsible for managing a setting’s value. The business requirements are that
|
||||
the user should not be allowed to overwrite an existing customization of a
|
||||
setting but can unset the setting and can give the setting a value if it is
|
||||
currently unset.
|
||||
|
||||
[Listing-18-18]: #Listing-18-18
|
||||
<a name="Listing-18-18"></a>
|
||||
|
||||
```rust
|
||||
let mut setting_value = Some(5);
|
||||
let new_setting_value = Some(10);
|
||||
|
@ -486,9 +510,12 @@ In all other cases (if either `setting_value` or `new_setting_value` are
|
|||
`new_setting_value` to become `setting_value`.
|
||||
|
||||
We can also use underscores in multiple places within one pattern to ignore
|
||||
particular values. Listing 18-19 shows an example of ignoring the second and
|
||||
particular values. [Listing 18-19][Listing-18-19] shows an example of ignoring the second and
|
||||
fourth values in a tuple of five items.
|
||||
|
||||
[Listing-18-19]: #Listing-18-19
|
||||
<a name="Listing-18-19"></a>
|
||||
|
||||
```rust
|
||||
let numbers = (2, 4, 8, 16, 32);
|
||||
|
||||
|
@ -510,12 +537,15 @@ If you create a variable but don’t use it anywhere, Rust will usually issue a
|
|||
warning because that could be a bug. But sometimes it’s useful to create a
|
||||
variable you won’t use yet, such as when you’re prototyping or just starting a
|
||||
project. In this situation, you can tell Rust not to warn you about the unused
|
||||
variable by starting the name of the variable with an underscore. In Listing
|
||||
18-20, we create two unused variables, but when we run this code, we should
|
||||
variable by starting the name of the variable with an underscore. In [Listing 18-20][Listing-18-20],
|
||||
we create two unused variables, but when we run this code, we should
|
||||
only get a warning about one of them.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-18-20]: #Listing-18-20
|
||||
<a name="Listing-18-20"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let _x = 5;
|
||||
|
@ -532,7 +562,10 @@ warning about not using the variable preceded by the underscore.
|
|||
Note that there is a subtle difference between using only `_` and using a name
|
||||
that starts with an underscore. The syntax `_x` still binds the value to the
|
||||
variable, whereas `_` doesn’t bind at all. To show a case where this
|
||||
distinction matters, Listing 18-21 will provide us with an error.
|
||||
distinction matters, [Listing 18-21][Listing-18-21] will provide us with an error.
|
||||
|
||||
[Listing-18-21]: #Listing-18-21
|
||||
<a name="Listing-18-21"></a>
|
||||
|
||||
```rust,ignore
|
||||
let s = Some(String::from("Hello!"));
|
||||
|
@ -549,9 +582,12 @@ underscore still binds the value, which might take ownership of the value</span>
|
|||
|
||||
We’ll receive an error because the `s` value will still be moved into `_s`,
|
||||
which prevents us from using `s` again. However, using the underscore by itself
|
||||
doesn’t ever bind to the value. Listing 18-22 will compile without any errors
|
||||
doesn’t ever bind to the value. [Listing 18-22][Listing-18-22] will compile without any errors
|
||||
because `s` doesn’t get moved into `_`.
|
||||
|
||||
[Listing-18-22]: #Listing-18-22
|
||||
<a name="Listing-18-22"></a>
|
||||
|
||||
```rust
|
||||
let s = Some(String::from("Hello!"));
|
||||
|
||||
|
@ -572,11 +608,14 @@ This code works just fine because we never bind `s` to anything; it isn’t move
|
|||
With values that have many parts, we can use the `..` syntax to use only a few
|
||||
parts and ignore the rest, avoiding the need to list underscores for each
|
||||
ignored value. The `..` pattern ignores any parts of a value that we haven’t
|
||||
explicitly matched in the rest of the pattern. In Listing 18-23, we have a
|
||||
explicitly matched in the rest of the pattern. In [Listing 18-23][Listing-18-23], we have a
|
||||
`Point` struct that holds a coordinate in three-dimensional space. In the
|
||||
`match` expression, we want to operate only on the `x` coordinate and ignore
|
||||
the values in the `y` and `z` fields.
|
||||
|
||||
[Listing-18-23]: #Listing-18-23
|
||||
<a name="Listing-18-23"></a>
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
|
@ -599,11 +638,14 @@ than having to list `y: _` and `z: _`, particularly when we’re working with
|
|||
structs that have lots of fields in situations where only one or two fields are
|
||||
relevant.
|
||||
|
||||
The syntax `..` will expand to as many values as it needs to be. Listing 18-24
|
||||
The syntax `..` will expand to as many values as it needs to be. [Listing 18-24][Listing-18-24]
|
||||
shows how to use `..` with a tuple.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-18-24]: #Listing-18-24
|
||||
<a name="Listing-18-24"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let numbers = (2, 4, 8, 16, 32);
|
||||
|
@ -624,11 +666,14 @@ In this code, the first and last value are matched with `first` and `last`. The
|
|||
|
||||
However, using `..` must be unambiguous. If it is unclear which values are
|
||||
intended for matching and which should be ignored, Rust will give us an error.
|
||||
Listing 18-25 shows an example of using `..` ambiguously, so it will not
|
||||
[Listing 18-25][Listing-18-25] shows an example of using `..` ambiguously, so it will not
|
||||
compile.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-18-25]: #Listing-18-25
|
||||
<a name="Listing-18-25"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let numbers = (2, 4, 8, 16, 32);
|
||||
|
@ -668,12 +713,15 @@ Let’s look at using `ref` to make references so ownership of the values isn’
|
|||
moved to variables in the pattern. Usually, when you match against a pattern,
|
||||
the variables introduced by the pattern are bound to a value. Rust’s ownership
|
||||
rules mean the value will be moved into the `match` or wherever you’re using
|
||||
the pattern. Listing 18-26 shows an example of a `match` that has a pattern
|
||||
the pattern. [Listing 18-26][Listing-18-26] shows an example of a `match` that has a pattern
|
||||
with a variable and then usage of the entire value in the `println!` statement
|
||||
later, after the `match`. This code will fail to compile because ownership of
|
||||
part of the `robot_name` value is transferred to the `name` variable in the
|
||||
pattern of the first `match` arm.
|
||||
|
||||
[Listing-18-26]: #Listing-18-26
|
||||
<a name="Listing-18-26"></a>
|
||||
|
||||
```rust,ignore
|
||||
let robot_name = Some(String::from("Bors"));
|
||||
|
||||
|
@ -703,7 +751,10 @@ reference in the value. Because `&` already has that meaning in patterns, we
|
|||
can’t use `&` to create a reference in a pattern.
|
||||
|
||||
Instead, to create a reference in a pattern, we use the `ref` keyword before
|
||||
the new variable, as shown in Listing 18-27.
|
||||
the new variable, as shown in [Listing 18-27][Listing-18-27].
|
||||
|
||||
[Listing-18-27]: #Listing-18-27
|
||||
<a name="Listing-18-27"></a>
|
||||
|
||||
```rust
|
||||
let robot_name = Some(String::from("Bors"));
|
||||
|
@ -726,9 +777,12 @@ to the data in `robot_name` rather than moving it.
|
|||
To create a mutable reference so we’re able to mutate a value matched in a
|
||||
pattern, we use `ref mut` instead of `&mut`. The reason is, again, that in
|
||||
patterns, the latter is for matching existing mutable references, not creating
|
||||
new ones. Listing 18-28 shows an example of a pattern creating a mutable
|
||||
new ones. [Listing 18-28][Listing-18-28] shows an example of a pattern creating a mutable
|
||||
reference.
|
||||
|
||||
[Listing-18-28]: #Listing-18-28
|
||||
<a name="Listing-18-28"></a>
|
||||
|
||||
```rust
|
||||
let mut robot_name = Some(String::from("Bors"));
|
||||
|
||||
|
@ -754,10 +808,13 @@ a `match` arm that must also match, along with the pattern matching, for that
|
|||
arm to be chosen. Match guards are useful for expressing more complex ideas
|
||||
than a pattern alone allows.
|
||||
|
||||
The condition can use variables created in the pattern. Listing 18-29 shows a
|
||||
The condition can use variables created in the pattern. [Listing 18-29][Listing-18-29] shows a
|
||||
`match` where the first arm has the pattern `Some(x)` and also has a match
|
||||
guard of `if x < 5`.
|
||||
|
||||
[Listing-18-29]: #Listing-18-29
|
||||
<a name="Listing-18-29"></a>
|
||||
|
||||
```rust
|
||||
let num = Some(4);
|
||||
|
||||
|
@ -783,15 +840,18 @@ therefore matches any `Some` variant.
|
|||
There is no way to express the `if x < 5` condition within a pattern, so the
|
||||
match guard gives us the ability to express this logic.
|
||||
|
||||
In Listing 18-11, we mentioned that we could use match guards to solve our
|
||||
In [Listing 18-11][Listing-18-11], we mentioned that we could use match guards to solve our
|
||||
pattern-shadowing problem. Recall that a new variable was created inside the
|
||||
pattern in the `match` expression instead of using the variable outside the
|
||||
`match`. That new variable meant we couldn’t test against the value of the
|
||||
outer variable. Listing 18-30 shows how we can use a match guard to fix this
|
||||
outer variable. [Listing 18-30][Listing-18-30] shows how we can use a match guard to fix this
|
||||
problem.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-18-30]: #Listing-18-30
|
||||
<a name="Listing-18-30"></a>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = Some(5);
|
||||
|
@ -823,12 +883,15 @@ we can look for a value that has the same value as the outer `y` by comparing
|
|||
`n` to `y`.
|
||||
|
||||
You can also use the *or* operator `|` in a match guard to specify multiple
|
||||
patterns; the match guard condition will apply to all the patterns. Listing
|
||||
18-31 shows the precedence of combining a match guard with a pattern that uses
|
||||
patterns; the match guard condition will apply to all the patterns. [Listing 18-31][Listing-18-31]
|
||||
shows the precedence of combining a match guard with a pattern that uses
|
||||
`|`. The important part of this example is that the `if y` match guard applies
|
||||
to `4`, `5`, *and* `6`, even though it might look like `if y` only applies to
|
||||
`6`.
|
||||
|
||||
[Listing-18-31]: #Listing-18-31
|
||||
<a name="Listing-18-31"></a>
|
||||
|
||||
```rust
|
||||
let x = 4;
|
||||
let y = false;
|
||||
|
@ -869,13 +932,16 @@ were applied only to the final value in the list of values specified using the
|
|||
### `@` Bindings
|
||||
|
||||
The *at* operator (`@`) lets us create a variable that holds a value at the
|
||||
same time we’re testing that value to see whether it matches a pattern. Listing
|
||||
18-32 shows an example where we want to test that a `Message::Hello` `id` field
|
||||
same time we’re testing that value to see whether it matches a pattern. [Listing 18-32][Listing-18-32]
|
||||
shows an example where we want to test that a `Message::Hello` `id` field
|
||||
is within the range `3...7`. But we also want to bind the value to the variable
|
||||
`id_variable` so we can use it in the code associated with the arm. We could
|
||||
name this variable `id`, the same as the field, but for this example we’ll use
|
||||
a different name.
|
||||
|
||||
[Listing-18-32]: #Listing-18-32
|
||||
<a name="Listing-18-32"></a>
|
||||
|
||||
```rust
|
||||
enum Message {
|
||||
Hello { id: i32 },
|
||||
|
@ -929,3 +995,28 @@ variables. We can create simple or complex patterns to suit our needs.
|
|||
|
||||
Next, for the penultimate chapter of the book, we’ll look at some advanced
|
||||
aspects of a variety of Rust’s features.
|
||||
|
||||
[Listing-18-11]: ch18-03-pattern-syntax.html#Listing-18-11
|
||||
[Listing-18-12]: ch18-03-pattern-syntax.html#Listing-18-12
|
||||
[Listing-18-13]: ch18-03-pattern-syntax.html#Listing-18-13
|
||||
[Listing-18-14]: ch18-03-pattern-syntax.html#Listing-18-14
|
||||
[Listing-18-15]: ch18-03-pattern-syntax.html#Listing-18-15
|
||||
[Listing-18-16]: ch18-03-pattern-syntax.html#Listing-18-16
|
||||
[Listing-18-17]: ch18-03-pattern-syntax.html#Listing-18-17
|
||||
[Listing-18-18]: ch18-03-pattern-syntax.html#Listing-18-18
|
||||
[Listing-18-19]: ch18-03-pattern-syntax.html#Listing-18-19
|
||||
[Listing-18-20]: ch18-03-pattern-syntax.html#Listing-18-20
|
||||
[Listing-18-21]: ch18-03-pattern-syntax.html#Listing-18-21
|
||||
[Listing-18-22]: ch18-03-pattern-syntax.html#Listing-18-22
|
||||
[Listing-18-23]: ch18-03-pattern-syntax.html#Listing-18-23
|
||||
[Listing-18-24]: ch18-03-pattern-syntax.html#Listing-18-24
|
||||
[Listing-18-25]: ch18-03-pattern-syntax.html#Listing-18-25
|
||||
[Listing-18-26]: ch18-03-pattern-syntax.html#Listing-18-26
|
||||
[Listing-18-27]: ch18-03-pattern-syntax.html#Listing-18-27
|
||||
[Listing-18-28]: ch18-03-pattern-syntax.html#Listing-18-28
|
||||
[Listing-18-29]: ch18-03-pattern-syntax.html#Listing-18-29
|
||||
[Listing-18-30]: ch18-03-pattern-syntax.html#Listing-18-30
|
||||
[Listing-18-31]: ch18-03-pattern-syntax.html#Listing-18-31
|
||||
[Listing-18-32]: ch18-03-pattern-syntax.html#Listing-18-32
|
||||
[Listing-6-5]: ch06-02-match.html#Listing-6-5
|
||||
[Listing-6-2]: ch06-01-defining-an-enum.html#Listing-6-2
|
||||
|
|
|
@ -85,9 +85,12 @@ By opting out of having Rust enforce these guarantees, you can give up
|
|||
guaranteed safety in exchange for greater performance or the ability to
|
||||
interface with another language or hardware where Rust’s guarantees don’t apply.
|
||||
|
||||
Listing 19-1 shows how to create an immutable and a mutable raw pointer from
|
||||
[Listing 19-1][Listing-19-1] shows how to create an immutable and a mutable raw pointer from
|
||||
references.
|
||||
|
||||
[Listing-19-1]: #Listing-19-1
|
||||
<a name="Listing-19-1"></a>
|
||||
|
||||
```rust
|
||||
let mut num = 5;
|
||||
|
||||
|
@ -108,12 +111,15 @@ pointers are valid, but we can’t make that assumption about just any raw
|
|||
pointer.
|
||||
|
||||
Next, we’ll create a raw pointer whose validity we can’t be so certain of.
|
||||
Listing 19-2 shows how to create a raw pointer to an arbitrary location in
|
||||
[Listing 19-2][Listing-19-2] shows how to create a raw pointer to an arbitrary location in
|
||||
memory. Trying to use arbitrary memory is undefined: there might be data at
|
||||
that address or there might not, the compiler might optimize the code so there
|
||||
is no memory access, or the program might error with a segmentation fault.
|
||||
Usually, there is no good reason to write code like this, but it is possible.
|
||||
|
||||
[Listing-19-2]: #Listing-19-2
|
||||
<a name="Listing-19-2"></a>
|
||||
|
||||
```rust
|
||||
let address = 0x012345usize;
|
||||
let r = address as *const i32;
|
||||
|
@ -123,9 +129,12 @@ let r = address as *const i32;
|
|||
memory address</span>
|
||||
|
||||
Recall that we can create raw pointers in safe code, but we can’t *dereference*
|
||||
raw pointers and read the data being pointed to. In Listing 19-3, we use the
|
||||
raw pointers and read the data being pointed to. In [Listing 19-3][Listing-19-3], we use the
|
||||
dereference operator `*` on a raw pointer that requires an `unsafe` block.
|
||||
|
||||
[Listing-19-3]: #Listing-19-3
|
||||
<a name="Listing-19-3"></a>
|
||||
|
||||
```rust
|
||||
let mut num = 5;
|
||||
|
||||
|
@ -144,7 +153,7 @@ unsafe {
|
|||
Creating a pointer does no harm; it’s only when we try to access the value that
|
||||
it points at that we might end up dealing with an invalid value.
|
||||
|
||||
Note also that in Listing 19-1 and 19-3, we created `*const i32` and `*mut i32`
|
||||
Note also that in [Listing 19-1][Listing-19-1] and 19-3, we created `*const i32` and `*mut i32`
|
||||
raw pointers that both pointed to the same memory location, where `num` is
|
||||
stored. If we instead tried to create an immutable and a mutable reference to
|
||||
`num`, the code would not have compiled because Rust’s ownership rules don’t
|
||||
|
@ -210,7 +219,10 @@ a common abstraction. As an example, let’s study a function from the standard
|
|||
library, `split_at_mut`, that requires some unsafe code and explore how we
|
||||
might implement it. This safe method is defined on mutable slices: it takes one
|
||||
slice and makes it two by splitting the slice at the index given as an
|
||||
argument. Listing 19-4 shows how to use `split_at_mut`.
|
||||
argument. [Listing 19-4][Listing-19-4] shows how to use `split_at_mut`.
|
||||
|
||||
[Listing-19-4]: #Listing-19-4
|
||||
<a name="Listing-19-4"></a>
|
||||
|
||||
```rust
|
||||
let mut v = vec![1, 2, 3, 4, 5, 6];
|
||||
|
@ -227,10 +239,13 @@ assert_eq!(b, &mut [4, 5, 6]);
|
|||
function</span>
|
||||
|
||||
We can’t implement this function using only safe Rust. An attempt might look
|
||||
something like Listing 19-5, which won’t compile. For simplicity, we’ll
|
||||
something like [Listing 19-5][Listing-19-5], which won’t compile. For simplicity, we’ll
|
||||
implement `split_at_mut` as a function rather than a method and only for slices
|
||||
of `i32` values rather than for a generic type `T`.
|
||||
|
||||
[Listing-19-5]: #Listing-19-5
|
||||
<a name="Listing-19-5"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
|
||||
let len = slice.len();
|
||||
|
@ -255,7 +270,7 @@ Then we return two mutable slices in a tuple: one from the start of the
|
|||
original slice to the `mid` index and another from `mid` to the end of the
|
||||
slice.
|
||||
|
||||
When we try to compile the code in Listing 19-5, we’ll get an error.
|
||||
When we try to compile the code in [Listing 19-5][Listing-19-5], we’ll get an error.
|
||||
|
||||
```text
|
||||
error[E0499]: cannot borrow `*slice` as mutable more than once at a time
|
||||
|
@ -275,9 +290,12 @@ Borrowing different parts of a slice is fundamentally okay because the two
|
|||
slices aren’t overlapping, but Rust isn’t smart enough to know this. When we
|
||||
know code is okay, but Rust doesn’t, it’s time to reach for unsafe code.
|
||||
|
||||
Listing 19-6 shows how to use an `unsafe` block, a raw pointer, and some calls
|
||||
[Listing 19-6][Listing-19-6] shows how to use an `unsafe` block, a raw pointer, and some calls
|
||||
to unsafe functions to make the implementation of `split_at_mut` work.
|
||||
|
||||
[Listing-19-6]: #Listing-19-6
|
||||
<a name="Listing-19-6"></a>
|
||||
|
||||
```rust
|
||||
use std::slice;
|
||||
|
||||
|
@ -328,10 +346,13 @@ abstraction to the unsafe code with an implementation of the function that uses
|
|||
`unsafe` code in a safe way, because it creates only valid pointers from the
|
||||
data this function has access to.
|
||||
|
||||
In contrast, the use of `slice::from_raw_parts_mut` in Listing 19-7 would
|
||||
In contrast, the use of `slice::from_raw_parts_mut` in [Listing 19-7][Listing-19-7] would
|
||||
likely crash when the slice is used. This code takes an arbitrary memory
|
||||
location and creates a slice 10,000 items long.
|
||||
|
||||
[Listing-19-7]: #Listing-19-7
|
||||
<a name="Listing-19-7"></a>
|
||||
|
||||
```rust
|
||||
use std::slice;
|
||||
|
||||
|
@ -358,7 +379,7 @@ and use of a *Foreign Function Interface (FFI)*. An FFI is a way for a
|
|||
programming language to define functions and enable a different (foreign)
|
||||
programming language to call those functions.
|
||||
|
||||
Listing 19-8 demonstrates how to set up an integration with the `abs` function
|
||||
[Listing 19-8][Listing-19-8] demonstrates how to set up an integration with the `abs` function
|
||||
from the C standard library. Functions declared within `extern` blocks are
|
||||
always unsafe to call from Rust code. The reason is that other languages don’t
|
||||
enforce Rust’s rules and guarantees, and Rust can’t check them, so
|
||||
|
@ -366,6 +387,9 @@ responsibility falls on the programmer to ensure safety.
|
|||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-8]: #Listing-19-8
|
||||
<a name="Listing-19-8"></a>
|
||||
|
||||
```rust
|
||||
extern "C" {
|
||||
fn abs(input: i32) -> i32;
|
||||
|
@ -418,12 +442,15 @@ Until now, we’ve not talked about *global variables*, which Rust does support
|
|||
but can be problematic with Rust’s ownership rules. If two threads are
|
||||
accessing the same mutable global variable, it can cause a data race.
|
||||
|
||||
In Rust, global variables are called *static* variables. Listing 19-9 shows an
|
||||
In Rust, global variables are called *static* variables. [Listing 19-9][Listing-19-9] shows an
|
||||
example declaration and use of a static variable with a string slice as a
|
||||
value.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-9]: #Listing-19-9
|
||||
<a name="Listing-19-9"></a>
|
||||
|
||||
```rust
|
||||
static HELLO_WORLD: &str = "Hello, world!";
|
||||
|
||||
|
@ -450,11 +477,14 @@ are allowed to duplicate their data whenever they’re used.
|
|||
|
||||
Another difference between constants and static variables is that static
|
||||
variables can be mutable. Accessing and modifying mutable static variables is
|
||||
*unsafe*. Listing 19-10 shows how to declare, access, and modify a mutable
|
||||
*unsafe*. [Listing 19-10][Listing-19-10] shows how to declare, access, and modify a mutable
|
||||
static variable named `COUNTER`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-10]: #Listing-19-10
|
||||
<a name="Listing-19-10"></a>
|
||||
|
||||
```rust
|
||||
static mut COUNTER: u32 = 0;
|
||||
|
||||
|
@ -494,7 +524,10 @@ The final action that works only with `unsafe` is implementing an unsafe trait.
|
|||
A trait is unsafe when at least one of its methods has some invariant that the
|
||||
compiler can’t verify. We can declare that a trait is `unsafe` by adding the
|
||||
`unsafe` keyword before `trait` and marking the implementation of the trait as
|
||||
`unsafe` too, as shown in Listing 19-11.
|
||||
`unsafe` too, as shown in [Listing 19-11][Listing-19-11].
|
||||
|
||||
[Listing-19-11]: #Listing-19-11
|
||||
<a name="Listing-19-11"></a>
|
||||
|
||||
```rust
|
||||
unsafe trait Foo {
|
||||
|
@ -529,3 +562,15 @@ isn’t wrong or even frowned upon. But it is trickier to get `unsafe` code
|
|||
correct because the compiler can’t help uphold memory safety. When you have a
|
||||
reason to use `unsafe` code, you can do so, and having the explicit `unsafe`
|
||||
annotation makes it easier to track down the source of problems if they occur.
|
||||
|
||||
[Listing-19-1]: ch19-01-unsafe-rust.html#Listing-19-1
|
||||
[Listing-19-2]: ch19-01-unsafe-rust.html#Listing-19-2
|
||||
[Listing-19-3]: ch19-01-unsafe-rust.html#Listing-19-3
|
||||
[Listing-19-4]: ch19-01-unsafe-rust.html#Listing-19-4
|
||||
[Listing-19-5]: ch19-01-unsafe-rust.html#Listing-19-5
|
||||
[Listing-19-6]: ch19-01-unsafe-rust.html#Listing-19-6
|
||||
[Listing-19-7]: ch19-01-unsafe-rust.html#Listing-19-7
|
||||
[Listing-19-8]: ch19-01-unsafe-rust.html#Listing-19-8
|
||||
[Listing-19-9]: ch19-01-unsafe-rust.html#Listing-19-9
|
||||
[Listing-19-10]: ch19-01-unsafe-rust.html#Listing-19-10
|
||||
[Listing-19-11]: ch19-01-unsafe-rust.html#Listing-19-11
|
||||
|
|
|
@ -18,11 +18,14 @@ lifetime. To explore lifetime subtyping, imagine we want to write a parser.
|
|||
We’ll use a structure called `Context` that holds a reference to the string
|
||||
we’re parsing. We’ll write a parser that will parse this string and return
|
||||
success or failure. The parser will need to borrow the `Context` to do the
|
||||
parsing. Listing 19-12 implements this parser code, except the code doesn’t
|
||||
parsing. [Listing 19-12][Listing-19-12] implements this parser code, except the code doesn’t
|
||||
have the required lifetime annotations, so it won’t compile.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-19-12]: #Listing-19-12
|
||||
<a name="Listing-19-12"></a>
|
||||
|
||||
```rust,ignore
|
||||
struct Context(&str);
|
||||
|
||||
|
@ -62,7 +65,7 @@ lifetimes involved.
|
|||
To get this code to compile, we need to fill in the lifetime parameters for the
|
||||
string slice in `Context` and the reference to the `Context` in `Parser`. The
|
||||
most straightforward way to do this is to use the same lifetime name
|
||||
everywhere, as shown in Listing 19-13. Recall from the “Lifetime Annotations in
|
||||
everywhere, as shown in [Listing 19-13][Listing-19-13]. Recall from the “Lifetime Annotations in
|
||||
Struct Definitions” section in Chapter 10 that each of `struct Context<'a>`,
|
||||
`struct Parser<'a>`, and `impl<'a>` is declaring a new lifetime parameter.
|
||||
While their names happen to all be the same, the three lifetime parameters
|
||||
|
@ -70,6 +73,9 @@ declared in this example aren’t related.
|
|||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-19-13]: #Listing-19-13
|
||||
<a name="Listing-19-13"></a>
|
||||
|
||||
```rust
|
||||
struct Context<'a>(&'a str);
|
||||
|
||||
|
@ -93,12 +99,15 @@ also lives as long as the reference to the `Context` in `Parser`. Rust’s
|
|||
compiler error message stated that lifetime parameters were required for these
|
||||
references, and we’ve now added lifetime parameters.
|
||||
|
||||
Next, in Listing 19-14, we’ll add a function that takes an instance of
|
||||
Next, in [Listing 19-14][Listing-19-14], we’ll add a function that takes an instance of
|
||||
`Context`, uses a `Parser` to parse that context, and returns what `parse`
|
||||
returns. This code doesn’t quite work.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-19-14]: #Listing-19-14
|
||||
<a name="Listing-19-14"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn parse_context(context: Context) -> Result<(), &str> {
|
||||
Parser { context: &context }.parse()
|
||||
|
@ -155,8 +164,8 @@ references in this code to always be valid. The `Parser` we’re creating and th
|
|||
`context` parameter go out of scope at the end of the function, because
|
||||
`parse_context` takes ownership of `context`.
|
||||
|
||||
To figure out why these errors occur, let’s look at the definitions in Listing
|
||||
19-13 again, specifically the references in the signature of the `parse` method:
|
||||
To figure out why these errors occur, let’s look at the definitions in [Listing 19-13][Listing-19-13]
|
||||
again, specifically the references in the signature of the `parse` method:
|
||||
|
||||
```rust,ignore
|
||||
fn parse(&self) -> Result<(), &str> {
|
||||
|
@ -205,7 +214,7 @@ different lifetimes and that the return value of `parse_context` is tied to the
|
|||
lifetime of the string slice in `Context`.
|
||||
|
||||
First, we’ll try giving `Parser` and `Context` different lifetime parameters,
|
||||
as shown in Listing 19-15. We’ll use `'s` and `'c` as lifetime parameter names
|
||||
as shown in [Listing 19-15][Listing-19-15]. We’ll use `'s` and `'c` as lifetime parameter names
|
||||
to clarify which lifetime goes with the string slice in `Context` and which
|
||||
goes with the reference to `Context` in `Parser`. Note that this solution won’t
|
||||
completely fix the problem, but it’s a start. We’ll look at why this fix isn’t
|
||||
|
@ -213,6 +222,9 @@ sufficient when we try to compile.
|
|||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-19-15]: #Listing-19-15
|
||||
<a name="Listing-19-15"></a>
|
||||
|
||||
```rust,ignore
|
||||
struct Context<'s>(&'s str);
|
||||
|
||||
|
@ -235,7 +247,7 @@ fn parse_context(context: Context) -> Result<(), &str> {
|
|||
for the references to the string slice and to `Context`</span>
|
||||
|
||||
We’ve annotated the lifetimes of the references in all the same places that we
|
||||
annotated them in Listing 19-13. But this time we used different parameters
|
||||
annotated them in [Listing 19-13][Listing-19-13]. But this time we used different parameters
|
||||
depending on whether the reference goes with the string slice or with
|
||||
`Context`. We’ve also added an annotation to the string slice part of the
|
||||
return value of `parse` to indicate that it goes with the lifetime of the
|
||||
|
@ -312,10 +324,13 @@ As an example, consider a type that is a wrapper over references. Recall the
|
|||
section in Chapter 15: its `borrow` and `borrow_mut` methods return the types
|
||||
`Ref` and `RefMut`, respectively. These types are wrappers over references that
|
||||
keep track of the borrowing rules at runtime. The definition of the `Ref`
|
||||
struct is shown in Listing 19-16, without lifetime bounds for now.
|
||||
struct is shown in [Listing 19-16][Listing-19-16], without lifetime bounds for now.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-19-16]: #Listing-19-16
|
||||
<a name="Listing-19-16"></a>
|
||||
|
||||
```rust,ignore
|
||||
struct Ref<'a, T>(&'a T);
|
||||
```
|
||||
|
@ -354,9 +369,12 @@ consider adding an explicit lifetime bound `T: 'a` so that the reference type
|
|||
`&'a T` does not outlive the data it points at
|
||||
```
|
||||
|
||||
Listing 19-17 shows how to apply this advice by specifying the lifetime bound
|
||||
[Listing 19-17][Listing-19-17] shows how to apply this advice by specifying the lifetime bound
|
||||
when we declare the generic type `T`.
|
||||
|
||||
[Listing-19-17]: #Listing-19-17
|
||||
<a name="Listing-19-17"></a>
|
||||
|
||||
```rust
|
||||
struct Ref<'a, T: 'a>(&'a T);
|
||||
```
|
||||
|
@ -369,10 +387,13 @@ type, but if it contains any references, the references must live at least as
|
|||
long as `'a`.
|
||||
|
||||
We could solve this problem in a different way, as shown in the definition of a
|
||||
`StaticRef` struct in Listing 19-18, by adding the `'static` lifetime bound on
|
||||
`StaticRef` struct in [Listing 19-18][Listing-19-18], by adding the `'static` lifetime bound on
|
||||
`T`. This means if `T` contains any references, they must have the `'static`
|
||||
lifetime.
|
||||
|
||||
[Listing-19-18]: #Listing-19-18
|
||||
<a name="Listing-19-18"></a>
|
||||
|
||||
```rust
|
||||
struct StaticRef<T: 'static>(&'static T);
|
||||
```
|
||||
|
@ -395,13 +416,16 @@ In Chapter 17 in the “Using Trait Objects that Allow for Values of Different
|
|||
Types” section, we discussed trait objects, consisting of a trait behind a
|
||||
reference, that allow us to use dynamic dispatch. We haven’t yet discussed what
|
||||
happens if the type implementing the trait in the trait object has a lifetime
|
||||
of its own. Consider Listing 19-19 where we have a trait `Red` and a struct
|
||||
of its own. Consider [Listing 19-19][Listing-19-19] where we have a trait `Red` and a struct
|
||||
`Ball`. The `Ball` struct holds a reference (and thus has a lifetime parameter)
|
||||
and also implements trait `Red`. We want to use an instance of `Ball` as the
|
||||
trait object `Box<Red>`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-19]: #Listing-19-19
|
||||
<a name="Listing-19-19"></a>
|
||||
|
||||
```rust
|
||||
trait Red { }
|
||||
|
||||
|
@ -441,3 +465,12 @@ bounds, the syntax adding a lifetime bound means that any implementor of the
|
|||
specified in the trait object bounds as those references.
|
||||
|
||||
Next, let’s look at some other advanced features that manage traits.
|
||||
|
||||
[Listing-19-12]: ch19-02-advanced-lifetimes.html#Listing-19-12
|
||||
[Listing-19-13]: ch19-02-advanced-lifetimes.html#Listing-19-13
|
||||
[Listing-19-14]: ch19-02-advanced-lifetimes.html#Listing-19-14
|
||||
[Listing-19-15]: ch19-02-advanced-lifetimes.html#Listing-19-15
|
||||
[Listing-19-16]: ch19-02-advanced-lifetimes.html#Listing-19-16
|
||||
[Listing-19-17]: ch19-02-advanced-lifetimes.html#Listing-19-17
|
||||
[Listing-19-18]: ch19-02-advanced-lifetimes.html#Listing-19-18
|
||||
[Listing-19-19]: ch19-02-advanced-lifetimes.html#Listing-19-19
|
||||
|
|
|
@ -23,7 +23,10 @@ standard library provides. The associated type is named `Item` and stands in
|
|||
for the type of the values the type implementing the `Iterator` trait is
|
||||
iterating over. In “The `Iterator` Trait and the `next` Method” section of
|
||||
Chapter 13, we mentioned that the definition of the `Iterator` trait is as
|
||||
shown in Listing 19-20.
|
||||
shown in [Listing 19-20][Listing-19-20].
|
||||
|
||||
[Listing-19-20]: #Listing-19-20
|
||||
<a name="Listing-19-20"></a>
|
||||
|
||||
```rust
|
||||
pub trait Iterator {
|
||||
|
@ -47,7 +50,7 @@ handle. So why use associated types?
|
|||
|
||||
Let’s examine the difference between the two concepts with an example from
|
||||
Chapter 13 that implements the `Iterator` trait on the `Counter` struct. In
|
||||
Listing 13-21, we specified that the `Item` type was `u32`:
|
||||
[Listing 13-21][Listing-13-21], we specified that the `Item` type was `u32`:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
|
@ -60,7 +63,10 @@ impl Iterator for Counter {
|
|||
```
|
||||
|
||||
This syntax seems comparable to that of generics. So why not just define the
|
||||
`Iterator` trait with generics, as shown in Listing 19-21?
|
||||
`Iterator` trait with generics, as shown in [Listing 19-21][Listing-19-21]?
|
||||
|
||||
[Listing-19-21]: #Listing-19-21
|
||||
<a name="Listing-19-21"></a>
|
||||
|
||||
```rust
|
||||
pub trait Iterator<T> {
|
||||
|
@ -71,7 +77,7 @@ pub trait Iterator<T> {
|
|||
<span class="caption">Listing 19-21: A hypothetical definition of the
|
||||
`Iterator` trait using generics</span>
|
||||
|
||||
The difference is that when using generics, as in Listing 19-21, we must
|
||||
The difference is that when using generics, as in [Listing 19-21][Listing-19-21], we must
|
||||
annotate the types in each implementation; because we can also implement
|
||||
`Iterator<String> for Counter` or any other type, we could have multiple
|
||||
implementations of `Iterator` for `Counter`. In other words, when a trait has a
|
||||
|
@ -81,7 +87,7 @@ the concrete types of the generic type parameters each time. When we use the
|
|||
indicate which implementation of `Iterator` we want to use.
|
||||
|
||||
With associated types, we don’t need to annotate types because we can’t
|
||||
implement a trait on a type multiple times. In Listing 19-20 with the
|
||||
implement a trait on a type multiple times. In [Listing 19-20][Listing-19-20] with the
|
||||
definition that uses associated types, we can only choose what the type of
|
||||
`Item` will be once, because there can only be one `impl Iterator for Counter`.
|
||||
We don’t have to specify that we want an iterator of `u32` values everywhere
|
||||
|
@ -102,12 +108,15 @@ overloading. *Operator overloading* is customizing the behavior of an operator
|
|||
Rust doesn’t allow you to create your own operators or overload arbitrary
|
||||
operators. But you can overload the operations and corresponding traits listed
|
||||
in `std::ops` by implementing the traits associated with the operator. For
|
||||
example, in Listing 19-22 we overload the `+` operator to add two `Point`
|
||||
example, in [Listing 19-22][Listing-19-22] we overload the `+` operator to add two `Point`
|
||||
instances together. We do this by implementing the `Add` trait on a `Point`
|
||||
struct:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-22]: #Listing-19-22
|
||||
<a name="Listing-19-22"></a>
|
||||
|
||||
```rust
|
||||
use std::ops::Add;
|
||||
|
||||
|
@ -169,10 +178,13 @@ default.
|
|||
We have two structs, `Millimeters` and `Meters`, holding values in different
|
||||
units. We want to add values in millimeters to values in meters and have the
|
||||
implementation of `Add` do the conversion correctly. We can implement `Add` for
|
||||
`Millimeters` with `Meters` as the `RHS`, as shown in Listing 19-23.
|
||||
`Millimeters` with `Meters` as the `RHS`, as shown in [Listing 19-23][Listing-19-23].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-19-23]: #Listing-19-23
|
||||
<a name="Listing-19-23"></a>
|
||||
|
||||
```rust
|
||||
use std::ops::Add;
|
||||
|
||||
|
@ -219,13 +231,16 @@ on one type. It’s also possible to implement a method directly on the type wit
|
|||
the same name as methods from traits.
|
||||
|
||||
When calling methods with the same name, you’ll need to tell Rust which one you
|
||||
want to use. Consider the code in Listing 19-24 where we’ve defined two traits,
|
||||
want to use. Consider the code in [Listing 19-24][Listing-19-24] where we’ve defined two traits,
|
||||
`Pilot` and `Wizard`, that both have a method called `fly`. We then implement
|
||||
both traits on a type `Human` that already has a method named `fly` implemented
|
||||
on it. Each `fly` method does something different.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-24]: #Listing-19-24
|
||||
<a name="Listing-19-24"></a>
|
||||
|
||||
```rust
|
||||
trait Pilot {
|
||||
fn fly(&self);
|
||||
|
@ -261,10 +276,13 @@ method and are implemented on the `Human` type, and a `fly` method is
|
|||
implemented on `Human` directly</span>
|
||||
|
||||
When we call `fly` on an instance of `Human`, the compiler defaults to calling
|
||||
the method that is directly implemented on the type, as shown in Listing 19-25.
|
||||
the method that is directly implemented on the type, as shown in [Listing 19-25][Listing-19-25].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-25]: #Listing-19-25
|
||||
<a name="Listing-19-25"></a>
|
||||
|
||||
```rust
|
||||
# trait Pilot {
|
||||
# fn fly(&self);
|
||||
|
@ -308,10 +326,13 @@ called the `fly` method implemented on `Human` directly.
|
|||
|
||||
To call the `fly` methods from either the `Pilot` trait or the `Wizard` trait,
|
||||
we need to use more explicit syntax to specify which `fly` method we mean.
|
||||
Listing 19-26 demonstrates this syntax.
|
||||
[Listing 19-26][Listing-19-26] demonstrates this syntax.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-26]: #Listing-19-26
|
||||
<a name="Listing-19-26"></a>
|
||||
|
||||
```rust
|
||||
# trait Pilot {
|
||||
# fn fly(&self);
|
||||
|
@ -355,7 +376,7 @@ want to call</span>
|
|||
Specifying the trait name before the method name clarifies to Rust which
|
||||
implementation of `fly` we want to call. We could also write
|
||||
`Human::fly(&person)`, which is equivalent to the `person.fly()` that we used
|
||||
in Listing 19-26, but this is a bit longer to write if we don’t need to
|
||||
in [Listing 19-26][Listing-19-26], but this is a bit longer to write if we don’t need to
|
||||
disambiguate.
|
||||
|
||||
Running this code prints the following:
|
||||
|
@ -373,12 +394,15 @@ trait to use based on the type of `self`.
|
|||
However, associated functions that are part of traits don’t have a `self`
|
||||
parameter. When two types in the same scope implement that trait, Rust can’t
|
||||
figure out which type you mean unless you use *fully qualified syntax*. For
|
||||
example, the `Animal` trait in Listing 19-27 has the associated function
|
||||
example, the `Animal` trait in [Listing 19-27][Listing-19-27] has the associated function
|
||||
`baby_name`, the implementation of `Animal` for the struct `Dog`, and the
|
||||
associated function `baby_name` defined on `Dog` directly.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-27]: #Listing-19-27
|
||||
<a name="Listing-19-27"></a>
|
||||
|
||||
```rust
|
||||
trait Animal {
|
||||
fn baby_name() -> String;
|
||||
|
@ -424,11 +448,14 @@ A baby dog is called a Spot
|
|||
This output isn’t what we wanted. We want to call the `baby_name` function that
|
||||
is part of the `Animal` trait that we implemented on `Dog` so the code prints
|
||||
`A baby dog is called a puppy`. The technique of specifying the trait name that
|
||||
we used in Listing 19-26 doesn’t help here; if we change `main` to the code in
|
||||
Listing 19-28, we’ll get a compilation error.
|
||||
we used in [Listing 19-26][Listing-19-26] doesn’t help here; if we change `main` to the code in
|
||||
[Listing 19-28][Listing-19-28], we’ll get a compilation error.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-28]: #Listing-19-28
|
||||
<a name="Listing-19-28"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
println!("A baby dog is called a {}", Animal::baby_name());
|
||||
|
@ -454,11 +481,14 @@ error[E0283]: type annotations required: cannot resolve `_: Animal`
|
|||
```
|
||||
|
||||
To disambiguate and tell Rust that we want to use the implementation of
|
||||
`Animal` for `Dog`, we need to use fully qualified syntax. Listing 19-29
|
||||
`Animal` for `Dog`, we need to use fully qualified syntax. [Listing 19-29][Listing-19-29]
|
||||
demonstrates how to use fully qualified syntax.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-29]: #Listing-19-29
|
||||
<a name="Listing-19-29"></a>
|
||||
|
||||
```rust
|
||||
# trait Animal {
|
||||
# fn baby_name() -> String;
|
||||
|
@ -535,10 +565,13 @@ functionality. Therefore, we need to specify that the `OutlinePrint` trait will
|
|||
work only for types that also implement `Display` and provide the functionality
|
||||
that `OutlinePrint` needs. We can do that in the trait definition by specifying
|
||||
`OutlinePrint: Display`. This technique is similar to adding a trait bound to
|
||||
the trait. Listing 19-30 shows an implementation of the `OutlinePrint` trait.
|
||||
the trait. [Listing 19-30][Listing-19-30] shows an implementation of the `OutlinePrint` trait.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-30]: #Listing-19-30
|
||||
<a name="Listing-19-30"></a>
|
||||
|
||||
```rust
|
||||
use std::fmt;
|
||||
|
||||
|
@ -635,10 +668,13 @@ As an example, let’s say we want to implement `Display` on `Vec<T>`, which the
|
|||
orphan rule prevents us from doing directly because the `Display` trait and the
|
||||
`Vec<T>` type are defined outside our crate. We can make a `Wrapper` struct
|
||||
that holds an instance of `Vec<T>`; then we can implement `Display` on
|
||||
`Wrapper` and use the `Vec<T>` value, as shown in Listing 19-31.
|
||||
`Wrapper` and use the `Vec<T>` value, as shown in [Listing 19-31][Listing-19-31].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-31]: #Listing-19-31
|
||||
<a name="Listing-19-31"></a>
|
||||
|
||||
```rust
|
||||
use std::fmt;
|
||||
|
||||
|
@ -678,3 +714,17 @@ methods we do want manually.
|
|||
Now you know how the newtype pattern is used in relation to traits; it’s also a
|
||||
useful pattern even when traits are not involved. Let’s switch focus and look
|
||||
at some advanced ways to interact with Rust’s type system.
|
||||
|
||||
[Listing-19-20]: ch19-03-advanced-traits.html#Listing-19-20
|
||||
[Listing-19-21]: ch19-03-advanced-traits.html#Listing-19-21
|
||||
[Listing-19-22]: ch19-03-advanced-traits.html#Listing-19-22
|
||||
[Listing-19-23]: ch19-03-advanced-traits.html#Listing-19-23
|
||||
[Listing-19-24]: ch19-03-advanced-traits.html#Listing-19-24
|
||||
[Listing-19-25]: ch19-03-advanced-traits.html#Listing-19-25
|
||||
[Listing-19-26]: ch19-03-advanced-traits.html#Listing-19-26
|
||||
[Listing-19-27]: ch19-03-advanced-traits.html#Listing-19-27
|
||||
[Listing-19-28]: ch19-03-advanced-traits.html#Listing-19-28
|
||||
[Listing-19-29]: ch19-03-advanced-traits.html#Listing-19-29
|
||||
[Listing-19-30]: ch19-03-advanced-traits.html#Listing-19-30
|
||||
[Listing-19-31]: ch19-03-advanced-traits.html#Listing-19-31
|
||||
[Listing-13-21]: ch13-02-iterators.html#Listing-13-21
|
||||
|
|
|
@ -14,7 +14,7 @@ discuss the `!` type and dynamically sized types.
|
|||
The newtype pattern is useful for tasks beyond those we’ve discussed so far,
|
||||
including statically enforcing that values are never confused and indicating
|
||||
the units of a value. You saw an example of using newtypes to indicate units in
|
||||
Listing 19-23: recall that the `Millimeters` and `Meters` structs wrapped `u32`
|
||||
[Listing 19-23][Listing-19-23]: recall that the `Millimeters` and `Meters` structs wrapped `u32`
|
||||
values in a newtype. If we wrote a function with a parameter of type
|
||||
`Millimeters`, we couldn’t compile a program that accidentally tried to call
|
||||
that function with a value of type `Meters` or a plain `u32`.
|
||||
|
@ -44,7 +44,7 @@ type Kilometers = i32;
|
|||
```
|
||||
|
||||
Now, the alias `Kilometers` is a *synonym* for `i32`; unlike the `Millimeters`
|
||||
and `Meters` types we created in Listing 19-23, `Kilometers` is not a separate,
|
||||
and `Meters` types we created in [Listing 19-23][Listing-19-23], `Kilometers` is not a separate,
|
||||
new type. Values that have the type `Kilometers` will be treated the same as
|
||||
values of type `i32`:
|
||||
|
||||
|
@ -71,7 +71,10 @@ Box<Fn() + Send + 'static>
|
|||
|
||||
Writing this lengthy type in function signatures and as type annotations all
|
||||
over the code can be tiresome and error prone. Imagine having a project full of
|
||||
code like that in Listing 19-32.
|
||||
code like that in [Listing 19-32][Listing-19-32].
|
||||
|
||||
[Listing-19-32]: #Listing-19-32
|
||||
<a name="Listing-19-32"></a>
|
||||
|
||||
```rust
|
||||
let f: Box<Fn() + Send + 'static> = Box::new(|| println!("hi"));
|
||||
|
@ -89,9 +92,12 @@ fn returns_long_type() -> Box<Fn() + Send + 'static> {
|
|||
<span class="caption">Listing 19-32: Using a long type in many places</span>
|
||||
|
||||
A type alias makes this code more manageable by reducing the repetition. In
|
||||
Listing 19-33, we’ve introduced an alias named `Thunk` for the verbose type and
|
||||
[Listing 19-33][Listing-19-33], we’ve introduced an alias named `Thunk` for the verbose type and
|
||||
can replace all uses of the type with the shorter alias `Thunk`.
|
||||
|
||||
[Listing-19-33]: #Listing-19-33
|
||||
<a name="Listing-19-33"></a>
|
||||
|
||||
```rust
|
||||
type Thunk = Box<Fn() + Send + 'static>;
|
||||
|
||||
|
@ -181,7 +187,10 @@ never are called *diverging functions*. We can’t create values of the type `!`
|
|||
so `bar` can never possibly return.
|
||||
|
||||
But what use is a type you can never create values for? Recall the code from
|
||||
Listing 2-5; we’ve reproduced part of it here in Listing 19-34.
|
||||
[Listing 2-5][Listing-2-5]; we’ve reproduced part of it here in [Listing 19-34][Listing-19-34].
|
||||
|
||||
[Listing-19-34]: #Listing-19-34
|
||||
<a name="Listing-19-34"></a>
|
||||
|
||||
```rust
|
||||
# let guess = "3";
|
||||
|
@ -211,7 +220,7 @@ let guess = match guess.trim().parse() {
|
|||
The type of `guess` in this code would have to be an integer *and* a string,
|
||||
and Rust requires that `guess` have only one type. So what does `continue`
|
||||
return? How were we allowed to return a `u32` from one arm and have another arm
|
||||
that ends with `continue` in Listing 19-34?
|
||||
that ends with `continue` in [Listing 19-34][Listing-19-34]?
|
||||
|
||||
As you might have guessed, `continue` has a `!` value. That is, when Rust
|
||||
computes the type of `guess`, it looks at both match arms, the former with a
|
||||
|
@ -239,7 +248,7 @@ impl<T> Option<T> {
|
|||
}
|
||||
```
|
||||
|
||||
In this code, the same thing happens as in the `match` in Listing 19-34: Rust
|
||||
In this code, the same thing happens as in the `match` in [Listing 19-34][Listing-19-34]: Rust
|
||||
sees that `val` has the type `T` and `panic!` has the type `!`, so the result
|
||||
of the overall `match` expression is `T`. This code works because `panic!`
|
||||
doesn’t produce a value; it ends the program. In the `None` case, we won’t be
|
||||
|
@ -347,3 +356,9 @@ Because the type might not be `Sized`, we need to use it behind some kind of
|
|||
pointer. In this case, we’ve chosen a reference.
|
||||
|
||||
Next, we’ll talk about functions and closures!
|
||||
|
||||
[Listing-19-23]: ch19-03-advanced-traits.html#Listing-19-23
|
||||
[Listing-2-5]: ch02-00-guessing-game-tutorial.html#Listing-2-5
|
||||
[Listing-19-32]: ch19-04-advanced-types.html#Listing-19-32
|
||||
[Listing-19-33]: ch19-04-advanced-types.html#Listing-19-33
|
||||
[Listing-19-34]: ch19-04-advanced-types.html#Listing-19-34
|
||||
|
|
|
@ -12,10 +12,13 @@ with function pointers will allow you to use functions as arguments to other
|
|||
functions. Functions coerce to the type `fn` (with a lowercase f), not to be
|
||||
confused with the `Fn` closure trait. The `fn` type is called a *function
|
||||
pointer*. The syntax for specifying that a parameter is a function pointer is
|
||||
similar to that of closures, as shown in Listing 19-35.
|
||||
similar to that of closures, as shown in [Listing 19-35][Listing-19-35].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-19-35]: #Listing-19-35
|
||||
<a name="Listing-19-35"></a>
|
||||
|
||||
```rust
|
||||
fn add_one(x: i32) -> i32 {
|
||||
x + 1
|
||||
|
@ -144,3 +147,5 @@ you to solutions.
|
|||
|
||||
Next, we’ll put everything we’ve discussed throughout the book into practice
|
||||
and do one more project!
|
||||
|
||||
[Listing-19-35]: ch19-05-advanced-functions-and-closures.html#Listing-19-35
|
||||
|
|
|
@ -6,7 +6,10 @@ concepts we covered in the final chapters, as well as recap some earlier
|
|||
lessons.
|
||||
|
||||
For our final project, we’ll make a web server that says “hello” and looks like
|
||||
Figure 20-1 in a web browser.
|
||||
[Figure 20-1][Figure-20-1] in a web browser.
|
||||
|
||||
[Figure-20-1]: #Figure-20-1
|
||||
<a name="Figure-20-1"></a>
|
||||
|
||||
![hello from rust](img/trpl20-01.png)
|
||||
|
||||
|
@ -31,3 +34,5 @@ level of abstraction we want to work with and can go to a lower level than is
|
|||
possible or practical in other languages. We’ll write the basic HTTP server and
|
||||
thread pool manually so you can learn the general ideas and techniques behind
|
||||
the crates you might use in the future.
|
||||
|
||||
[Figure-20-1]: ch20-00-final-project-a-web-server.html#Figure-20-1
|
||||
|
|
|
@ -31,12 +31,15 @@ $ cargo new hello --bin
|
|||
$ cd hello
|
||||
```
|
||||
|
||||
Now enter the code in Listing 20-1 in *src/main.rs* to start. This code will
|
||||
Now enter the code in [Listing 20-1][Listing-20-1] in *src/main.rs* to start. This code will
|
||||
listen at the address `127.0.0.1:7878` for incoming TCP streams. When it gets
|
||||
an incoming stream, it will print `Connection established!`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-20-1]: #Listing-20-1
|
||||
<a name="Listing-20-1"></a>
|
||||
|
||||
```rust,no_run
|
||||
use std::net::TcpListener;
|
||||
|
||||
|
@ -135,10 +138,13 @@ separate the concerns of first getting a connection and then taking some action
|
|||
with the connection, we’ll start a new function for processing connections. In
|
||||
this new `handle_connection` function, we’ll read data from the TCP stream and
|
||||
print it so we can see the data being sent from the browser. Change the code to
|
||||
look like Listing 20-2.
|
||||
look like [Listing 20-2][Listing-20-2].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-20-2]: #Listing-20-2
|
||||
<a name="Listing-20-2"></a>
|
||||
|
||||
```rust,no_run
|
||||
use std::io::prelude::*;
|
||||
use std::net::TcpStream;
|
||||
|
@ -291,10 +297,13 @@ The status code 200 is the standard success response. The text is a tiny
|
|||
successful HTTP response. Let’s write this to the stream as our response to a
|
||||
successful request! From the `handle_connection` function, remove the
|
||||
`println!` that was printing the request data and replace it with the code in
|
||||
Listing 20-3.
|
||||
[Listing 20-3][Listing-20-3].
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-20-3]: #Listing-20-3
|
||||
<a name="Listing-20-3"></a>
|
||||
|
||||
```rust
|
||||
# use std::io::prelude::*;
|
||||
# use std::net::TcpStream;
|
||||
|
@ -334,11 +343,14 @@ and response!
|
|||
|
||||
Let’s implement the functionality for returning more than a blank page. Create
|
||||
a new file, *hello.html*, in the root of your project directory, not in the
|
||||
*src* directory. You can input any HTML you want; Listing 20-4 shows one
|
||||
*src* directory. You can input any HTML you want; [Listing 20-4][Listing-20-4] shows one
|
||||
possibility.
|
||||
|
||||
<span class="filename">Filename: hello.html</span>
|
||||
|
||||
[Listing-20-4]: #Listing-20-4
|
||||
<a name="Listing-20-4"></a>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
@ -358,11 +370,14 @@ response</span>
|
|||
|
||||
This is a minimal HTML5 document with a heading and some text. To return this
|
||||
from the server when a request is received, we’ll modify `handle_connection` as
|
||||
shown in Listing 20-5 to read the HTML file, add it to the response as a body,
|
||||
shown in [Listing 20-5][Listing-20-5] to read the HTML file, add it to the response as a body,
|
||||
and send it.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-20-5]: #Listing-20-5
|
||||
<a name="Listing-20-5"></a>
|
||||
|
||||
```rust
|
||||
# use std::io::prelude::*;
|
||||
# use std::net::TcpStream;
|
||||
|
@ -391,7 +406,7 @@ body of the response</span>
|
|||
We’ve added a line at the top to bring the standard library’s `File` into
|
||||
scope. The code for opening a file and reading the contents should look
|
||||
familiar; we used it in Chapter 12 when we read the contents of a file for our
|
||||
I/O project in Listing 12-4.
|
||||
I/O project in [Listing 12-4][Listing-12-4].
|
||||
|
||||
Next, we use `format!` to add the file’s contents as the body of the success
|
||||
response.
|
||||
|
@ -412,12 +427,15 @@ Right now, our web server will return the HTML in the file no matter what the
|
|||
client requested. Let’s add functionality to check that the browser is
|
||||
requesting */* before returning the HTML file and return an error if the
|
||||
browser requests anything else. For this we need to modify `handle_connection`,
|
||||
as shown in Listing 20-6. This new code checks the content of the request
|
||||
as shown in [Listing 20-6][Listing-20-6]. This new code checks the content of the request
|
||||
received against what we know a request for */* looks like and adds `if` and
|
||||
`else` blocks to treat requests differently.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-20-6]: #Listing-20-6
|
||||
<a name="Listing-20-6"></a>
|
||||
|
||||
```rust
|
||||
# use std::io::prelude::*;
|
||||
# use std::net::TcpStream;
|
||||
|
@ -464,15 +482,18 @@ to all other requests.
|
|||
Run this code now and request *127.0.0.1:7878*; you should get the HTML in
|
||||
*hello.html*. If you make any other request, such as
|
||||
*127.0.0.1:7878/something-else*, you’ll get a connection error like those you
|
||||
saw when running the code in Listing 20-1 and Listing 20-2.
|
||||
saw when running the code in [Listing 20-1][Listing-20-1] and [Listing 20-2][Listing-20-2].
|
||||
|
||||
Now let’s add the code in Listing 20-7 to the `else` block to return a response
|
||||
Now let’s add the code in [Listing 20-7][Listing-20-7] to the `else` block to return a response
|
||||
with the status code 404, which signals that the content for the request was
|
||||
not found. We’ll also return some HTML for a page to render in the browser
|
||||
indicating the response to the end user.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-20-7]: #Listing-20-7
|
||||
<a name="Listing-20-7"></a>
|
||||
|
||||
```rust
|
||||
# use std::io::prelude::*;
|
||||
# use std::net::TcpStream;
|
||||
|
@ -503,10 +524,13 @@ Here, our response has a status line with status code 404 and the reason
|
|||
phrase `NOT FOUND`. We’re still not returning headers, and the body of the
|
||||
response will be the HTML in the file *404.html*. You’ll need to create a
|
||||
*404.html* file next to *hello.html* for the error page; again feel free to use
|
||||
any HTML you want or use the example HTML in Listing 20-8.
|
||||
any HTML you want or use the example HTML in [Listing 20-8][Listing-20-8].
|
||||
|
||||
<span class="filename">Filename: 404.html</span>
|
||||
|
||||
[Listing-20-8]: #Listing-20-8
|
||||
<a name="Listing-20-8"></a>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
@ -536,11 +560,14 @@ differences are the status line and the filename. Let’s make the code more
|
|||
concise by pulling out those differences into separate `if` and `else` lines
|
||||
that will assign the values of the status line and the filename to variables;
|
||||
we can then use those variables unconditionally in the code to read the file
|
||||
and write the response. Listing 20-9 shows the resulting code after replacing
|
||||
and write the response. [Listing 20-9][Listing-20-9] shows the resulting code after replacing
|
||||
the large `if` and `else` blocks.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-20-9]: #Listing-20-9
|
||||
<a name="Listing-20-9"></a>
|
||||
|
||||
```rust
|
||||
# use std::io::prelude::*;
|
||||
# use std::net::TcpStream;
|
||||
|
@ -584,8 +611,8 @@ The previously duplicated code is now outside the `if` and `else` blocks and
|
|||
uses the `status_line` and `filename` variables. This makes it easier to see
|
||||
the difference between the two cases, and it means we have only one place to
|
||||
update the code if we want to change how the file reading and response writing
|
||||
work. The behavior of the code in Listing 20-9 will be the same as that in
|
||||
Listing 20-8.
|
||||
work. The behavior of the code in [Listing 20-9][Listing-20-9] will be the same as that in
|
||||
[Listing 20-8][Listing-20-8].
|
||||
|
||||
Awesome! We now have a simple web server in approximately 40 lines of Rust code
|
||||
that responds to one request with a page of content and responds to all other
|
||||
|
@ -595,3 +622,14 @@ Currently, our server runs in a single thread, meaning it can only serve one
|
|||
request at a time. Let’s examine how that can be a problem by simulating some
|
||||
slow requests. Then we’ll fix it so our server can handle multiple requests at
|
||||
once.
|
||||
|
||||
[Listing-12-4]: ch12-02-reading-a-file.html#Listing-12-4
|
||||
[Listing-20-1]: ch20-01-single-threaded.html#Listing-20-1
|
||||
[Listing-20-2]: ch20-01-single-threaded.html#Listing-20-2
|
||||
[Listing-20-3]: ch20-01-single-threaded.html#Listing-20-3
|
||||
[Listing-20-4]: ch20-01-single-threaded.html#Listing-20-4
|
||||
[Listing-20-5]: ch20-01-single-threaded.html#Listing-20-5
|
||||
[Listing-20-6]: ch20-01-single-threaded.html#Listing-20-6
|
||||
[Listing-20-7]: ch20-01-single-threaded.html#Listing-20-7
|
||||
[Listing-20-8]: ch20-01-single-threaded.html#Listing-20-8
|
||||
[Listing-20-9]: ch20-01-single-threaded.html#Listing-20-9
|
||||
|
|
|
@ -11,12 +11,15 @@ this, but first, we’ll look at the problem in action.
|
|||
### Simulating a Slow Request in the Current Server Implementation
|
||||
|
||||
We’ll look at how a slow-processing request can affect other requests made to
|
||||
our current server implementation. Listing 20-10 implements handling a request
|
||||
our current server implementation. [Listing 20-10][Listing-20-10] implements handling a request
|
||||
to */sleep* with a simulated slow response that will cause the server to sleep
|
||||
for 5 seconds before responding.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-20-10]: #Listing-20-10
|
||||
<a name="Listing-20-10"></a>
|
||||
|
||||
```rust
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
@ -118,11 +121,14 @@ what we should change next to get the code to work.
|
|||
First, let’s explore how our code might look if it did create a new thread for
|
||||
every connection. As mentioned earlier, this isn’t our final plan due to the
|
||||
problems with potentially spawning an unlimited number of threads, but it is a
|
||||
starting point. Listing 20-11 shows the changes to make to `main` to spawn a
|
||||
starting point. [Listing 20-11][Listing-20-11] shows the changes to make to `main` to spawn a
|
||||
new thread to handle each stream within the `for` loop.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-20-11]: #Listing-20-11
|
||||
<a name="Listing-20-11"></a>
|
||||
|
||||
```rust,no_run
|
||||
# use std::thread;
|
||||
# use std::io::prelude::*;
|
||||
|
@ -157,11 +163,14 @@ new threads without any limit.
|
|||
|
||||
We want our thread pool to work in a similar, familiar way so switching from
|
||||
threads to a thread pool doesn’t require large changes to the code that uses
|
||||
our API. Listing 20-12 shows the hypothetical interface for a `ThreadPool`
|
||||
our API. [Listing 20-12][Listing-20-12] shows the hypothetical interface for a `ThreadPool`
|
||||
struct we want to use instead of `thread::spawn`.
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
[Listing-20-12]: #Listing-20-12
|
||||
<a name="Listing-20-12"></a>
|
||||
|
||||
```rust,no_run
|
||||
# use std::thread;
|
||||
# use std::io::prelude::*;
|
||||
|
@ -200,7 +209,7 @@ compile, but we’ll try so the compiler can guide us in how to fix it.
|
|||
|
||||
#### Building the `ThreadPool` Struct Using Compiler Driven Development
|
||||
|
||||
Make the changes in Listing 20-12 to *src/main.rs*, and then let’s use the
|
||||
Make the changes in [Listing 20-12][Listing-20-12] to *src/main.rs*, and then let’s use the
|
||||
compiler errors from `cargo check` to drive our development. Here is the first
|
||||
error we get:
|
||||
|
||||
|
@ -411,10 +420,13 @@ negative number of threads makes no sense. However, a pool with zero threads
|
|||
also makes no sense, yet zero is a perfectly valid `usize`. We’ll add code to
|
||||
check that `size` is greater than zero before we return a `ThreadPool` instance
|
||||
and have the program panic if it receives a zero by using the `assert!` macro,
|
||||
as shown in Listing 20-13.
|
||||
as shown in [Listing 20-13][Listing-20-13].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-13]: #Listing-20-13
|
||||
<a name="Listing-20-13"></a>
|
||||
|
||||
```rust
|
||||
# pub struct ThreadPool;
|
||||
impl ThreadPool {
|
||||
|
@ -445,8 +457,8 @@ Try running `cargo doc --open` and clicking the `ThreadPool` struct to see what
|
|||
the generated docs for `new` look like!
|
||||
|
||||
Instead of adding the `assert!` macro as we’ve done here, we could make `new`
|
||||
return a `Result` like we did with `Config::new` in the I/O project in Listing
|
||||
12-9. But we’ve decided in this case that trying to create a thread pool
|
||||
return a `Result` like we did with `Config::new` in the I/O project in [Listing 12-9][Listing-12-9].
|
||||
But we’ve decided in this case that trying to create a thread pool
|
||||
without any threads should be an unrecoverable error. If you’re feeling
|
||||
ambitious, try to write a version of `new` with the following signature to
|
||||
compare both versions:
|
||||
|
@ -474,7 +486,7 @@ closure returns. Let’s try using `JoinHandle` too and see what happens. In our
|
|||
case, the closures we’re passing to the thread pool will handle the connection
|
||||
and not return anything, so `T` will be the unit type `()`.
|
||||
|
||||
The code in Listing 20-14 will compile but doesn’t create any threads yet.
|
||||
The code in [Listing 20-14][Listing-20-14] will compile but doesn’t create any threads yet.
|
||||
We’ve changed the definition of `ThreadPool` to hold a vector of
|
||||
`thread::JoinHandle<()>` instances, initialized the vector with a capacity of
|
||||
`size`, set up a `for` loop that will run some code to create the threads, and
|
||||
|
@ -482,6 +494,9 @@ returned a `ThreadPool` instance containing them.
|
|||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-14]: #Listing-20-14
|
||||
<a name="Listing-20-14"></a>
|
||||
|
||||
```rust,ignore
|
||||
use std::thread;
|
||||
|
||||
|
@ -529,7 +544,7 @@ succeed.
|
|||
|
||||
#### A `Worker` Struct Responsible for Sending Code from the `ThreadPool` to a Thread
|
||||
|
||||
We left a comment in the `for` loop in Listing 20-14 regarding the creation of
|
||||
We left a comment in the `for` loop in [Listing 20-14][Listing-20-14] regarding the creation of
|
||||
threads. Here, we’ll look at how we actually create threads. The standard
|
||||
library provides `thread::spawn` as a way to create threads, and
|
||||
`thread::spawn` expects to get some code the thread should run as soon as the
|
||||
|
@ -565,12 +580,15 @@ We’ll implement the code that sends the closure to the thread after we have
|
|||
a new `Worker` with that `id`, and store the worker in the vector.
|
||||
|
||||
If you’re up for a challenge, try implementing these changes on your own before
|
||||
looking at the code in Listing 20-15.
|
||||
looking at the code in [Listing 20-15][Listing-20-15].
|
||||
|
||||
Ready? Here is Listing 20-15 with one way to make the preceding modifications.
|
||||
Ready? Here is [Listing 20-15][Listing-20-15] with one way to make the preceding modifications.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-15]: #Listing-20-15
|
||||
<a name="Listing-20-15"></a>
|
||||
|
||||
```rust
|
||||
use std::thread;
|
||||
|
||||
|
@ -658,12 +676,15 @@ Here is the plan:
|
|||
and execute the closures of any jobs it receives.
|
||||
|
||||
Let’s start by creating a channel in `ThreadPool::new` and holding the sending
|
||||
side in the `ThreadPool` instance, as shown in Listing 20-16. The `Job` struct
|
||||
side in the `ThreadPool` instance, as shown in [Listing 20-16][Listing-20-16]. The `Job` struct
|
||||
doesn’t hold anything for now but will be the type of item we’re sending down
|
||||
the channel.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-16]: #Listing-20-16
|
||||
<a name="Listing-20-16"></a>
|
||||
|
||||
```rust
|
||||
# use std::thread;
|
||||
// --snip--
|
||||
|
@ -723,10 +744,13 @@ sending end. This will successfully compile, still with warnings.
|
|||
Let’s try passing a receiving end of the channel into each worker as the thread
|
||||
pool creates the channel. We know we want to use the receiving end in the
|
||||
thread that the workers spawn, so we’ll reference the `receiver` parameter in
|
||||
the closure. The code in Listing 20-17 won’t quite compile yet.
|
||||
the closure. The code in [Listing 20-17][Listing-20-17] won’t quite compile yet.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-17]: #Listing-20-17
|
||||
<a name="Listing-20-17"></a>
|
||||
|
||||
```rust,ignore
|
||||
impl ThreadPool {
|
||||
// --snip--
|
||||
|
@ -802,10 +826,13 @@ Recall the thread-safe smart pointers discussed in Chapter 16: to share
|
|||
ownership across multiple threads and allow the threads to mutate the value, we
|
||||
need to use `Arc<Mutex<T>>`. The `Arc` type will let multiple workers own the
|
||||
receiver, and `Mutex` will ensure that only one worker gets a job from the
|
||||
receiver at a time. Listing 20-18 shows the changes we need to make.
|
||||
receiver at a time. [Listing 20-18][Listing-20-18] shows the changes we need to make.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-18]: #Listing-20-18
|
||||
<a name="Listing-20-18"></a>
|
||||
|
||||
```rust
|
||||
# use std::thread;
|
||||
# use std::sync::mpsc;
|
||||
|
@ -878,10 +905,13 @@ Let’s finally implement the `execute` method on `ThreadPool`. We’ll also cha
|
|||
`Job` from a struct to a type alias for a trait object that holds the type of
|
||||
closure that `execute` receives. As discussed in the “Creating Type Synonyms
|
||||
with Type Aliases” section of Chapter 19, type aliases allow us to make long
|
||||
types shorter. Look at Listing 20-19.
|
||||
types shorter. Look at [Listing 20-19][Listing-20-19].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-19]: #Listing-20-19
|
||||
<a name="Listing-20-19"></a>
|
||||
|
||||
```rust
|
||||
// --snip--
|
||||
# pub struct ThreadPool {
|
||||
|
@ -925,10 +955,13 @@ But we’re not quite done yet! In the worker, our closure being passed to
|
|||
`thread::spawn` still only *references* the receiving end of the channel.
|
||||
Instead, we need the closure to loop forever, asking the receiving end of the
|
||||
channel for a job and running the job when it gets one. Let’s make the change
|
||||
shown in Listing 20-20 to `Worker::new`.
|
||||
shown in [Listing 20-20][Listing-20-20] to `Worker::new`.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-20]: #Listing-20-20
|
||||
<a name="Listing-20-20"></a>
|
||||
|
||||
```rust,ignore
|
||||
// --snip--
|
||||
|
||||
|
@ -994,7 +1027,7 @@ the value inside the `Box<T>` will be: recall in Chapter 15 that we used
|
|||
`Box<T>` precisely because we had something of an unknown size that we wanted
|
||||
to store in a `Box<T>` to get a value of a known size.
|
||||
|
||||
As you saw in Listing 17-15, we can write methods that use the syntax `self:
|
||||
As you saw in [Listing 17-15][Listing-17-15], we can write methods that use the syntax `self:
|
||||
Box<Self>`, which allows the method to take ownership of a `Self` value stored
|
||||
in a `Box<T>`. That’s exactly what we want to do here, but unfortunately Rust
|
||||
won’t let us: the part of Rust that implements behavior when a closure is
|
||||
|
@ -1003,7 +1036,7 @@ understand that it could use `self: Box<Self>` in this situation to take
|
|||
ownership of the closure and move the closure out of the `Box<T>`.
|
||||
|
||||
Rust is still a work in progress with places where the compiler could be
|
||||
improved, but in the future, the code in Listing 20-20 should work just fine.
|
||||
improved, but in the future, the code in [Listing 20-20][Listing-20-20] should work just fine.
|
||||
People just like you are working to fix this and other issues! After you’ve
|
||||
finished this book, we would love for you to join in.
|
||||
|
||||
|
@ -1014,10 +1047,13 @@ we can call it. This involves defining a new trait `FnBox` with the method
|
|||
`call_box` that will use `self: Box<Self>` in its signature, defining `FnBox`
|
||||
for any type that implements `FnOnce()`, changing our type alias to use the new
|
||||
trait, and changing `Worker` to use the `call_box` method. These changes are
|
||||
shown in Listing 20-21.
|
||||
shown in [Listing 20-21][Listing-20-21].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-21]: #Listing-20-21
|
||||
<a name="Listing-20-21"></a>
|
||||
|
||||
```rust,ignore
|
||||
trait FnBox {
|
||||
fn call_box(self: Box<Self>);
|
||||
|
@ -1127,10 +1163,13 @@ overloaded if the server receives a lot of requests. If we make a request to
|
|||
thread run them.
|
||||
|
||||
After learning about the `while let` loop in Chapter 18, you might be wondering
|
||||
why we didn’t write the worker thread code as shown in Listing 20-22.
|
||||
why we didn’t write the worker thread code as shown in [Listing 20-22][Listing-20-22].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-22]: #Listing-20-22
|
||||
<a name="Listing-20-22"></a>
|
||||
|
||||
```rust,ignore
|
||||
// --snip--
|
||||
|
||||
|
@ -1173,3 +1212,19 @@ rather than outside it, the `MutexGuard` returned from the `lock` method is
|
|||
dropped as soon as the `let job` statement ends. This ensures that the lock is
|
||||
held during the call to `recv`, but it is released before the call to
|
||||
`job.call_box()`, allowing multiple requests to be serviced concurrently.
|
||||
|
||||
[Listing-17-15]: ch17-03-oo-design-patterns.html#Listing-17-15
|
||||
[Listing-20-10]: ch20-02-multithreaded.html#Listing-20-10
|
||||
[Listing-20-11]: ch20-02-multithreaded.html#Listing-20-11
|
||||
[Listing-20-12]: ch20-02-multithreaded.html#Listing-20-12
|
||||
[Listing-20-13]: ch20-02-multithreaded.html#Listing-20-13
|
||||
[Listing-20-14]: ch20-02-multithreaded.html#Listing-20-14
|
||||
[Listing-20-15]: ch20-02-multithreaded.html#Listing-20-15
|
||||
[Listing-20-16]: ch20-02-multithreaded.html#Listing-20-16
|
||||
[Listing-20-17]: ch20-02-multithreaded.html#Listing-20-17
|
||||
[Listing-20-18]: ch20-02-multithreaded.html#Listing-20-18
|
||||
[Listing-20-19]: ch20-02-multithreaded.html#Listing-20-19
|
||||
[Listing-20-20]: ch20-02-multithreaded.html#Listing-20-20
|
||||
[Listing-20-21]: ch20-02-multithreaded.html#Listing-20-21
|
||||
[Listing-20-22]: ch20-02-multithreaded.html#Listing-20-22
|
||||
[Listing-12-9]: ch12-03-improving-error-handling-and-modularity.html#Listing-12-9
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
## Graceful Shutdown and Cleanup
|
||||
|
||||
The code in Listing 20-21 is responding to requests asynchronously through the
|
||||
The code in [Listing 20-21][Listing-20-21] is responding to requests asynchronously through the
|
||||
use of a thread pool, as we intended. We get some warnings about the `workers`,
|
||||
`id`, and `thread` fields that we’re not using in a direct way that reminds us
|
||||
we’re not cleaning up anything. When we use the less elegant <span
|
||||
|
@ -18,11 +18,14 @@ accept only two requests before gracefully shutting down its thread pool.
|
|||
|
||||
Let’s start with implementing `Drop` on our thread pool. When the pool is
|
||||
dropped, our threads should all join to make sure they finish their work.
|
||||
Listing 20-23 shows a first attempt at a `Drop` implementation; this code won’t
|
||||
[Listing 20-23][Listing-20-23] shows a first attempt at a `Drop` implementation; this code won’t
|
||||
quite work yet.
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-23]: #Listing-20-23
|
||||
<a name="Listing-20-23"></a>
|
||||
|
||||
```rust,ignore
|
||||
impl Drop for ThreadPool {
|
||||
fn drop(&mut self) {
|
||||
|
@ -58,8 +61,8 @@ error[E0507]: cannot move out of borrowed content
|
|||
The error tells us we can’t call `join` because we only have a mutable borrow
|
||||
of each `worker` and `join` takes ownership of its argument. To solve this
|
||||
issue, we need to move the thread out of the `Worker` instance that owns
|
||||
`thread` so `join` can consume the thread. We did this in Listing 17-15: if
|
||||
`Worker` holds an `Option<thread::JoinHandle<()>>` instead, we can call the
|
||||
`thread` so `join` can consume the thread. We did this in [Listing 17-15][Listing-17-15]: if
|
||||
`Worker` holds an `Option<thread::JoinHandle<()>` instead, we can call the
|
||||
`take` method on the `Option` to move the value out of the `Some` variant and
|
||||
leave a `None` variant in its place. In other words, a `Worker` that is running
|
||||
will have a `Some` variant in `thread`, and when we want to clean up a
|
||||
|
@ -178,10 +181,13 @@ thread should run, or it will be a `Terminate` variant that will cause the
|
|||
thread to exit its loop and stop.
|
||||
|
||||
We need to adjust the channel to use values of type `Message` rather than type
|
||||
`Job`, as shown in Listing 20-24.
|
||||
`Job`, as shown in [Listing 20-24][Listing-20-24].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-24]: #Listing-20-24
|
||||
<a name="Listing-20-24"></a>
|
||||
|
||||
```rust,ignore
|
||||
pub struct ThreadPool {
|
||||
workers: Vec<Worker>,
|
||||
|
@ -248,12 +254,15 @@ received, and the thread will break out of the loop if the `Terminate` variant
|
|||
is received.
|
||||
|
||||
With these changes, the code will compile and continue to function in the same
|
||||
way as it did after Listing 20-21. But we’ll get a warning because we aren’t
|
||||
way as it did after [Listing 20-21][Listing-20-21]. But we’ll get a warning because we aren’t
|
||||
creating any messages of the `Terminate` variety. Let’s fix this warning by
|
||||
changing our `Drop` implementation to look like Listing 20-25.
|
||||
changing our `Drop` implementation to look like [Listing 20-25][Listing-20-25].
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
[Listing-20-25]: #Listing-20-25
|
||||
<a name="Listing-20-25"></a>
|
||||
|
||||
```rust,ignore
|
||||
impl Drop for ThreadPool {
|
||||
fn drop(&mut self) {
|
||||
|
@ -302,10 +311,13 @@ messages as there are workers, each worker will receive a terminate message
|
|||
before `join` is called on its thread.
|
||||
|
||||
To see this code in action, let’s modify `main` to accept only two requests
|
||||
before gracefully shutting down the server, as shown in Listing 20-26.
|
||||
before gracefully shutting down the server, as shown in [Listing 20-26][Listing-20-26].
|
||||
|
||||
<span class="filename">Filename: src/bin/main.rs</span>
|
||||
|
||||
[Listing-20-26]: #Listing-20-26
|
||||
<a name="Listing-20-26"></a>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
|
||||
|
@ -577,3 +589,10 @@ joining us on this tour of Rust. You’re now ready to implement your own Rust
|
|||
projects and help with other peoples’ projects. Keep in mind that there is a
|
||||
welcoming community of other Rustaceans who would love to help you with any
|
||||
challenges you encounter on your Rust journey.
|
||||
|
||||
[Listing-17-15]: ch17-03-oo-design-patterns.html#Listing-17-15
|
||||
[Listing-20-23]: ch20-03-graceful-shutdown-and-cleanup.html#Listing-20-23
|
||||
[Listing-20-24]: ch20-03-graceful-shutdown-and-cleanup.html#Listing-20-24
|
||||
[Listing-20-25]: ch20-03-graceful-shutdown-and-cleanup.html#Listing-20-25
|
||||
[Listing-20-26]: ch20-03-graceful-shutdown-and-cleanup.html#Listing-20-26
|
||||
[Listing-20-21]: ch20-02-multithreaded.html#Listing-20-21
|
||||
|
|
Loading…
Reference in New Issue