Propagate changes for ch8 to src

This commit is contained in:
Carol (Nichols || Goulding) 2022-05-29 19:39:49 -04:00
parent c12ec364aa
commit ac16184a7f
No known key found for this signature in database
GPG Key ID: E907EE5A736F87D4
16 changed files with 205 additions and 219 deletions

View File

@ -1,9 +1,14 @@
fn main() {
// ANCHOR: here
{
let v = vec![1, 2, 3, 4];
let v = vec![1, 2, 3, 4, 5];
// do stuff with v
} // <- v goes out of scope and is freed here
// ANCHOR_END: here
let third: &i32 = &v[2];
println!("The third element is {}", third);
let third: Option<&i32> = v.get(2);
match third {
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
}
// ANCHOR_END: here
}

View File

@ -2,13 +2,7 @@ fn main() {
// ANCHOR: here
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
println!("The third element is {}", third);
let third: Option<&i32> = v.get(2);
match third {
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
}
let does_not_exist = &v[100];
let does_not_exist = v.get(100);
// ANCHOR_END: here
}

View File

@ -1,8 +1,11 @@
fn main() {
// ANCHOR: here
let v = vec![1, 2, 3, 4, 5];
let mut v = vec![1, 2, 3, 4, 5];
let does_not_exist = &v[100];
let does_not_exist = v.get(100);
let first = &v[0];
v.push(6);
println!("The first element is: {}", first);
// ANCHOR_END: here
}

View File

@ -1,11 +1,8 @@
fn main() {
// ANCHOR: here
let mut v = vec![1, 2, 3, 4, 5];
let first = &v[0];
v.push(6);
println!("The first element is: {}", first);
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
}
// ANCHOR_END: here
}

View File

@ -1,8 +1,8 @@
fn main() {
// ANCHOR: here
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;
}
// ANCHOR_END: here
}

View File

@ -1,8 +1,15 @@
fn main() {
// ANCHOR: here
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50;
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
// ANCHOR_END: here
}

View File

@ -1,15 +1,9 @@
fn main() {
// ANCHOR: here
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
{
let v = vec![1, 2, 3, 4];
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
// ANCHOR_END: here
// do stuff with v
} // <- v goes out of scope and is freed here
// ANCHOR_END: here
}

View File

@ -2,10 +2,12 @@ fn main() {
// ANCHOR: here
use std::collections::HashMap;
let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let mut scores = HashMap::new();
let mut scores: HashMap<_, _> =
teams.into_iter().zip(initial_scores.into_iter()).collect();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
let team_name = String::from("Blue");
let score = scores.get(&team_name);
// ANCHOR_END: here
}

View File

@ -5,9 +5,8 @@ fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
scores.insert(String::from("Blue"), 25);
let team_name = String::from("Blue");
let score = scores.get(&team_name);
println!("{:?}", scores);
// ANCHOR_END: here
}

View File

@ -3,9 +3,10 @@ fn main() {
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Blue"), 25);
scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);
println!("{:?}", scores);
// ANCHOR_END: here

View File

@ -2,12 +2,15 @@ fn main() {
// ANCHOR: here
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
let text = "hello world wonderful world";
scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);
let mut map = HashMap::new();
println!("{:?}", scores);
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
println!("{:?}", map);
// ANCHOR_END: here
}

View File

@ -1,16 +0,0 @@
fn main() {
// ANCHOR: here
use std::collections::HashMap;
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
println!("{:?}", map);
// ANCHOR_END: here
}

View File

@ -63,56 +63,39 @@ make it mutable using the `mut` keyword, as discussed in Chapter 3. The numbers
we place inside are all of type `i32`, and Rust infers this from the data, so
we dont 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.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-04/src/main.rs:here}}
```
<span class="caption">Listing 8-4: Showing where the vector and its elements
are dropped</span>
When the vector gets dropped, all of its contents are also dropped, meaning
those integers it holds will be cleaned up. This may seem like a
straightforward point but it can get complicated when you start to introduce
references to the elements of the vector. Lets tackle that next!
### Reading Elements of Vectors
There are two ways to reference a value stored in a vector: via indexing or
using the `get` method. In the following examples, weve 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, with indexing
Listing 8-4 shows both methods of accessing a value in a vector, with indexing
syntax and the `get` method.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-05/src/main.rs:here}}
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-04/src/main.rs:here}}
```
<span class="caption">Listing 8-5: Using indexing syntax or the `get` method to
<span class="caption">Listing 8-4: Using indexing syntax or the `get` method to
access an item in a vector</span>
Note two details here. First, we use the index value of `2` to get the third
element because vectors are indexed by number, starting at zero. Second, we get
the third element by either using `&` and `[]`, which gives us a reference, or
using the `get` method with the index passed as an argument, which gives us an
`Option<&T>`.
Note a few details here. We use the index value of `2` to get the third element
because vectors are indexed by number, starting at zero. Using `&` and `[]`
gives us a reference to the element at the index value. When we use the `get`
method with the index passed as an argument, we get an `Option<&T>` that we can
use with `match`.
The reason Rust provides these two ways to reference an element is so you can
choose how the program behaves when you try to use an index value outside the
range of existing elements. As an example, lets see what happens when we have
a vector of five elements and then we try to access an element at index 100
with each technique, as shown in Listing 8-6.
with each technique, as shown in Listing 8-5.
```rust,should_panic,panics
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-06/src/main.rs:here}}
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-05/src/main.rs:here}}
```
<span class="caption">Listing 8-6: Attempting to access the element at index
<span class="caption">Listing 8-5: Attempting to access the element at index
100 in a vector containing five elements</span>
When we run this code, the first `[]` method will cause the program to panic
@ -135,25 +118,27 @@ 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 cant have mutable and immutable references in the same
scope. That rule applies in Listing 8-7, where we hold an immutable reference
scope. That rule applies in Listing 8-6, where we hold an immutable reference
to the first element in a vector and try to add an element to the end. This
program wont work if we also try to refer to that element later in the
function:
```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-07/src/main.rs:here}}
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-06/src/main.rs:here}}
```
<span class="caption">Listing 8-7: Attempting to add an element to a vector
<span class="caption">Listing 8-6: Attempting to add an element to a vector
while holding a reference to an item</span>
Compiling this code will result in this error:
```console
{{#include ../listings/ch08-common-collections/listing-08-07/output.txt}}
{{#include ../listings/ch08-common-collections/listing-08-06/output.txt}}
```
The code in Listing 8-7 might look like it should work: why should a reference
The code in Listing 8-6 might look like it should work: why should a reference
to the first element care about changes at the end of the vector? This error is
due to the way vectors work: because vectors put the values next to each other
in memory, adding a new element onto the end of the vector might require
@ -169,34 +154,41 @@ ending up in that situation.
### Iterating over the Values in a Vector
To access each element in a vector in turn, we would iterate through all of the
elements rather than use indices to access one at a time. Listing 8-8 shows how
elements rather than use indices to access one at a time. Listing 8-7 shows how
to use a `for` loop to get immutable references to each element in a vector of
`i32` values and print them.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-07/src/main.rs:here}}
```
<span class="caption">Listing 8-7: Printing each element in a vector by
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-8
will add `50` to each element.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-08/src/main.rs:here}}
```
<span class="caption">Listing 8-8: Printing each element in a vector by
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
will add `50` to each element.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-09/src/main.rs:here}}
```
<span class="caption">Listing 8-9: Iterating over mutable references to
<span class="caption">Listing 8-8: Iterating over mutable references to
elements in a vector</span>
To change the value that the mutable reference refers to, we have to use the
`*` dereference operator to get to the value in `i` before we can use the
`+=` operator. Well talk more about the dereference operator in the
[“Following the Pointer to the Value with the Dereference Operator”][deref]<!-- ignore -->
`*` dereference operator to get to the value in `i` before we can use the `+=`
operator. Well talk more about the dereference operator in the [“Following the
Pointer to the Value with the Dereference Operator”][deref]<!-- ignore -->
section of Chapter 15.
Iterating over a vector, whether immutably or mutably, is safe because of the
borrow checker's rules. If we attempted to insert or remove items in the `for`
loop bodies in Listing 8-7 and Listing 8-8, we would get a compiler error
similar to the one we got with the code in Listing 8-6. The reference to the
vector that the `for` loop holds prevents simultaneous modification of the
whole vector.
### Using an Enum to Store Multiple Types
Vectors can only store values that are the same type. This can be inconvenient;
@ -210,13 +202,13 @@ 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 all the enum variants will be considered the same type: that
of the enum. Then we can create a vector to hold that enum and so, ultimately,
holds different types. Weve demonstrated this in Listing 8-10.
holds different types. Weve demonstrated this in Listing 8-9.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-10/src/main.rs:here}}
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-09/src/main.rs:here}}
```
<span class="caption">Listing 8-10: Defining an `enum` to store values of
<span class="caption">Listing 8-9: Defining an `enum` to store values of
different types in one vector</span>
Rust needs to know what types will be in the vector at compile time so it knows
@ -234,8 +226,26 @@ object, which well cover in Chapter 17.
Now that weve discussed some of the most common ways to use vectors, be sure
to review [the API documentation][vec-api]<!-- ignore --> 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. Lets
move on to the next collection type: `String`!
addition to `push`, a `pop` method removes and returns the last element.
### 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-10.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-10/src/main.rs:here}}
```
<span class="caption">Listing 8-10: Showing where the vector and its elements
are dropped</span>
When the vector gets dropped, all of its contents are also dropped, meaning the
integers it holds will be cleaned up. The borrow checker ensures that any
references to contents of a vector are only used while the vector itself is
valid.
Lets move on to the next collection type: `String`!
[data-types]: ch03-02-data-types.html#data-types
[nomicon]: ../nomicon/vec/vec.html

View File

@ -33,20 +33,13 @@ of those types. Although this section is largely about `String`, both types are
used heavily in Rusts standard library, and both `String` and string slices
are UTF-8 encoded.
Rusts standard library also includes a number of other string types, such as
`OsString`, `OsStr`, `CString`, and `CStr`. Library crates can provide even
more options for storing string data. See how those names all end in `String`
or `Str`? They refer to owned and borrowed variants, just like the `String` and
`str` types youve seen previously. These string types can store text in
different encodings or be represented in memory in a different way, for
example. We wont discuss these other string types in this chapter; see their
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, because `String` is actually implemented as a wrapper around a vector
of bytes with some extra guarantees, restrictions, and capabilities. An example
of a function that works the same way with `Vec<T>` and `String` is the `new`
function to create an instance, shown in Listing 8-11.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-11/src/main.rs:here}}
@ -166,9 +159,9 @@ this:
fn add(self, s: &str) -> String {
```
In the standard library, youll see `add` defined using generics. Here, weve
substituted in concrete types for the generic ones, which is what happens when
we call this method with `String` values. Well discuss generics in Chapter 10.
In the standard library, you'll see `add` defined using generics and associated
types. Here, weve substituted in concrete types, which is what happens when we
call this method with `String` values. Well discuss generics in Chapter 10.
This signature gives us the clues we need to understand the tricky bits of the
`+` operator.
@ -382,7 +375,7 @@ for b in "Зд".bytes() {
}
```
This code will print the four bytes that make up this `String`:
This code will print the four bytes that make up this string:
```text
208
@ -410,4 +403,10 @@ strings than is apparent in other programming languages, but it prevents you
from having to handle errors involving non-ASCII characters later in your
development life cycle.
The good news is that the standard library offers a lot of functionality built
off the `String` and `&str` types to help handle these complex situations
correctly. Be sure to check out the documentation for useful methods like
`contains` for searching in a string and `replace` for substituting parts of a
string with another string.
Lets switch to something a bit less complex: hash maps!

View File

@ -39,34 +39,40 @@ standard library; theres no built-in macro to construct them, for example.
Just like vectors, hash maps store their data on the heap. This `HashMap` has
keys of type `String` and values of type `i32`. Like vectors, hash maps are
homogeneous: all of the keys must have the same type, and all of the values
must have the same type.
homogeneous: all of the keys must have the same type as each other, and all of
the values must have the same type.
Another way of constructing a hash map is by using iterators and the `collect`
method on a vector of tuples, where each tuple consists of a key and its value.
Well be going into more detail about iterators and their associated methods in
the [”Processing a Series of Items with Iterators” section of Chapter
13][iterators]<!-- ignore -->. The `collect` method gathers data into a number
of collection types, including `HashMap`. For example, if we had the team names
and initial scores in two separate vectors, we could use the `zip` method to
create an iterator of tuples where “Blue” is paired with 10, and so forth. Then
we could use the `collect` method to turn that iterator of tuples into a hash
map, as shown in Listing 8-21.
### 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-21.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-21/src/main.rs:here}}
```
<span class="caption">Listing 8-21: Creating a hash map from a list of teams
and a list of scores</span>
<span class="caption">Listing 8-21: Accessing the score for the Blue team
stored in the hash map</span>
The type annotation `HashMap<_, _>` is needed here because its possible to
`collect` into many different data structures and Rust doesnt know which you
want unless you specify. For the parameters for the key and value types,
however, we use underscores, and Rust can infer the types that the hash map
contains based on the types of the data in the vectors. In Listing 8-21, the
key type will be `String` and the value type will be `i32`, just as in Listing
8-20.
Here, `score` will have the value thats associated with the Blue team, and the
result will be `10`. The `get` method returns an `Option<&V>`; if theres no
value for that key in the hash map, `get` will return `None`. This program
handles the `Option` by calling `unwrap_or` to set `score` to zero if `scores`
doesn't have an entry for the key.
We can iterate over each key/value pair in a hash map in a similar manner as we
do with vectors, using a `for` loop:
```rust
{{#rustdoc_include ../listings/ch08-common-collections/no-listing-03-iterate-over-hashmap/src/main.rs:here}}
```
This code will print each pair in an arbitrary order:
```text
Yellow: 50
Blue: 10
```
### Hash Maps and Ownership
@ -91,83 +97,60 @@ the [“Validating References with
Lifetimes”][validating-references-with-lifetimes]<!-- ignore --> 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.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-23/src/main.rs:here}}
```
<span class="caption">Listing 8-23: Accessing the score for the Blue team
stored in the hash map</span>
Here, `score` will have the value thats associated with the Blue team, and the
result will be `Some(&10)`. The result is wrapped in `Some` because `get`
returns an `Option<&V>`; if theres no value for that key in the hash map,
`get` will return `None`. The program will need to handle the `Option` in one
of the ways that we covered in Chapter 6.
We can iterate over each key/value pair in a hash map in a similar manner as we
do with vectors, using a `for` loop:
```rust
{{#rustdoc_include ../listings/ch08-common-collections/no-listing-03-iterate-over-hashmap/src/main.rs:here}}
```
This code will print each pair in an arbitrary order:
```text
Yellow: 50
Blue: 10
```
### Updating a Hash Map
Although the number of key and value pairs is growable, each key can only have
one value associated with it at a time. When you want to change the data in a
hash map, you have to decide how to handle the case when a key already has a
value assigned. You could replace the old value with the new value, completely
disregarding the old value. You could keep the old value and ignore the new
value, only adding the new value if the key *doesnt* already have a value. Or
you could combine the old value and the new value. Lets look at how to do each
of these!
Although the number of key and value pairs is growable, each unique key can
only have one value associated with it at a time (but not vice versa: for
example, both the Blue team and the Yellow team could have value 10 stored in
the `scores` hash map).
When you want to change the data in a hash map, you have to decide how to
handle the case when a key already has a value assigned. You could replace the
old value with the new value, completely disregarding the old value. You could
keep the old value and ignore the new value, only adding the new value if the
key *doesnt* already have a value. Or you could combine the old value and the
new value. Lets look at how to do each of these!
#### Overwriting a Value
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-23 calls `insert` twice, the hash map will
only contain one key/value pair because were inserting the value for the Blue
teams key both times.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-24/src/main.rs:here}}
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-23/src/main.rs:here}}
```
<span class="caption">Listing 8-24: Replacing a value stored with a particular
<span class="caption">Listing 8-23: Replacing a value stored with a particular
key</span>
This code will print `{"Blue": 25}`. The original value of `10` has been
overwritten.
#### Only Inserting a Value If the Key Has No Value
<!-- Old headings. Do not remove or links may break. -->
<a id="only-inserting-a-value-if-the-key-has-no-value"></a>
Its common to check whether a particular key has a value and, if it doesnt,
insert a value for it. Hash maps have a special API for this called `entry`
that takes the key you want to check as a parameter. The return value of the
`entry` method is an enum called `Entry` that represents a value that might or
might not exist. Lets say we want to check whether the key for the Yellow team
has a value associated with it. If it doesnt, 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.
#### Adding a Key and Value Only If a Key Isnt Present
Its common to check whether a particular key already exists in the hash map
with a value then take the following actions: if the key does exist in the hash
map, the existing value should remain the way it is. If the key doesnt exist,
insert it and a value for it.
Hash maps have a special API for this called `entry` that takes the key you
want to check as a parameter. The return value of the `entry` method is an enum
called `Entry` that represents a value that might or might not exist. Lets say
we want to check whether the key for the Yellow team has a value associated
with it. If it doesnt, we want to insert the value 50, and the same for the
Blue team. Using the `entry` API, the code looks like Listing 8-24.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-25/src/main.rs:here}}
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-24/src/main.rs:here}}
```
<span class="caption">Listing 8-25: Using the `entry` method to only insert if
<span class="caption">Listing 8-24: Using the `entry` method to only insert if
the key does not already have a value</span>
The `or_insert` method on `Entry` is defined to return a mutable reference to
@ -176,7 +159,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-24 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 doesnt have a value already. The second call to
`entry` will not change the hash map because the Blue team already has the
@ -185,19 +168,24 @@ value 10.
#### Updating a Value Based on the Old Value
Another common use case for hash maps is to look up a keys 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-25 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 weve
seen that word. If its the first time weve seen a word, well first insert
the value 0.
```rust
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-26/src/main.rs:here}}
{{#rustdoc_include ../listings/ch08-common-collections/listing-08-25/src/main.rs:here}}
```
<span class="caption">Listing 8-26: Counting occurrences of words using a hash
<span class="caption">Listing 8-25: Counting occurrences of words using a hash
map that stores words and counts</span>
This code will print `{"world": 2, "hello": 1, "wonderful": 1}`. You might see
the same key/value pairs printed in a different order: recall from the
[“Accessing Values in a Hash Map”][access]<!-- ignore --> section that
iterating over a hash map happens in an arbitrary order.
This code will print `{"world": 2, "hello": 1, "wonderful": 1}`. The
`split_whitespace` method returns an iterator over sub-slices, separated by
whitespace, of the value in `text`. The `or_insert` method returns a mutable
@ -249,6 +237,6 @@ and hash maps have that will be helpful for these exercises!
Were getting into more complex programs in which operations can fail, so, its
a perfect time to discuss error handling. Well do that next!
[iterators]: ch13-02-iterators.html
[validating-references-with-lifetimes]:
ch10-03-lifetime-syntax.html#validating-references-with-lifetimes
[access]: #accessing-values-in-a-hash-map