mirror of https://github.com/rust-lang/book
Propagate changes for ch8 to src
This commit is contained in:
parent
c12ec364aa
commit
ac16184a7f
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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 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.
|
||||
|
||||
```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. Let’s 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, 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, 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, let’s 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 can’t 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 won’t 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. We’ll 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. We’ll 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. We’ve demonstrated this in Listing 8-10.
|
||||
holds different types. We’ve 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 we’ll cover in Chapter 17.
|
|||
Now that we’ve 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. Let’s
|
||||
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.
|
||||
|
||||
Let’s move on to the next collection type: `String`!
|
||||
|
||||
[data-types]: ch03-02-data-types.html#data-types
|
||||
[nomicon]: ../nomicon/vec/vec.html
|
||||
|
|
|
@ -33,20 +33,13 @@ of those types. Although this section is largely about `String`, both types are
|
|||
used heavily in Rust’s standard library, and both `String` and string slices
|
||||
are UTF-8 encoded.
|
||||
|
||||
Rust’s 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 you’ve seen previously. These string types can store text in
|
||||
different encodings or be represented in memory in a different way, for
|
||||
example. We won’t 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, you’ll see `add` defined using generics. Here, we’ve
|
||||
substituted in concrete types for the generic ones, which is what happens when
|
||||
we call this method with `String` values. We’ll discuss generics in Chapter 10.
|
||||
In the standard library, you'll see `add` defined using generics and associated
|
||||
types. Here, we’ve substituted in concrete types, which is what happens when we
|
||||
call this method with `String` values. We’ll 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.
|
||||
|
||||
Let’s switch to something a bit less complex: hash maps!
|
||||
|
|
|
@ -39,34 +39,40 @@ standard library; there’s 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.
|
||||
We’ll 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 it’s possible to
|
||||
`collect` into many different data structures and Rust doesn’t 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 that’s associated with the Blue team, and the
|
||||
result will be `10`. The `get` method returns an `Option<&V>`; if there’s 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 that’s 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 there’s 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 *doesn’t* already have a value. Or
|
||||
you could combine the old value and the new value. Let’s 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 *doesn’t* already have a value. Or you could combine the old value and the
|
||||
new value. Let’s 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 we’re inserting the value for the Blue
|
||||
team’s 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>
|
||||
|
||||
It’s common to check whether a particular key has a value and, if it doesn’t,
|
||||
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. 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.
|
||||
#### Adding a Key and Value Only If a Key Isn’t Present
|
||||
|
||||
It’s 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 doesn’t 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. 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-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 doesn’t 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 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-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 we’ve
|
||||
seen that word. If it’s the first time we’ve seen a word, we’ll 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!
|
|||
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!
|
||||
|
||||
[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
|
||||
|
|
Loading…
Reference in New Issue