mirror of
https://github.com/rust-lang/book.git
synced 2026-09-15 03:08:53 -04:00
Merge pull request #1025 from pduzinki/duplicate-listing-numbers
listing/figure numbering in chapter 15 corrected
This commit is contained in:
@@ -35,7 +35,7 @@ for clean up? -->
|
||||
this code gets run. It's hard to experience the cleaning up unless we print
|
||||
something. /Carol -->
|
||||
|
||||
Listing 15-8 shows a `CustomSmartPointer` struct whose only custom
|
||||
Listing 15-16 shows a `CustomSmartPointer` struct whose only custom
|
||||
functionality is that it will print out `Dropping CustomSmartPointer!` when the
|
||||
instance goes out of scope. This will demonstrate when Rust runs the `drop`
|
||||
function:
|
||||
@@ -69,7 +69,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-8: A `CustomSmartPointer` struct that
|
||||
<span class="caption">Listing 15-16: A `CustomSmartPointer` struct that
|
||||
implements the `Drop` trait, where we would put our clean up code.</span>
|
||||
|
||||
The `Drop` trait is included in the prelude, so we don’t need to import it. We
|
||||
@@ -122,7 +122,7 @@ up a value early. One example is when using smart pointers that manage locks;
|
||||
you may want to force the `drop` method that releases the lock to run so that
|
||||
other code in the same scope can acquire the lock. First, let’s see what
|
||||
happens if we try to call the `Drop` trait’s `drop` method ourselves by
|
||||
modifying the `main` function from Listing 15-8 as shown in Listing 15-9:
|
||||
modifying the `main` function from Listing 15-16 as shown in Listing 15-17:
|
||||
|
||||
<!-- Above: I'm not following why we are doing this, if it's not necessary and
|
||||
we aren't going to cover it now anyway -- can you lay out why we're discussing
|
||||
@@ -140,7 +140,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-9: Attempting to call the `drop` method from
|
||||
<span class="caption">Listing 15-17: Attempting to call the `drop` method from
|
||||
the `Drop` trait manually to clean up early</span>
|
||||
|
||||
If we try to compile this, we’ll get this error:
|
||||
@@ -171,7 +171,7 @@ force 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. `std::mem::drop` is in the prelude, so we can modify `main` from
|
||||
Listing 15-8 to call the `drop` function as shown in Listing 15-10:
|
||||
Listing 15-16 to call the `drop` function as shown in Listing 15-18:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
@@ -194,7 +194,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-10: Calling `std::mem::drop` to explicitly
|
||||
<span class="caption">Listing 15-18: Calling `std::mem::drop` to explicitly
|
||||
drop a value before it goes out of scope</span>
|
||||
|
||||
Running this code will print the following:
|
||||
|
||||
@@ -36,11 +36,11 @@ concurrency will cover how to do reference counting in multithreaded programs.
|
||||
|
||||
Let’s return to our cons list example from Listing 15-6, as we defined it using
|
||||
`Box<T>`. This time, we want to create two lists that both share ownership of a
|
||||
third list, which conceptually will look something like Figure 15-11:
|
||||
third list, which conceptually will look something like Figure 15-19:
|
||||
|
||||
<img alt="Two lists that share ownership of a third list" src="img/trpl15-03.svg" class="center" />
|
||||
|
||||
<span class="caption">Figure 15-11: Two lists, `b` and `c`, sharing ownership
|
||||
<span class="caption">Figure 15-19: Two lists, `b` and `c`, sharing ownership
|
||||
of a third list, `a`</span>
|
||||
|
||||
We’ll create list `a` that contains 5 and then 10, then make two more lists:
|
||||
@@ -49,7 +49,7 @@ then continue on to the first `a` list containing 5 and 10. In other words,
|
||||
both lists will try to share the first list containing 5 and 10.
|
||||
|
||||
Trying to implement this using our definition of `List` with `Box<T>` won’t
|
||||
work, as shown in Listing 15-12:
|
||||
work, as shown in Listing 15-20:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
@@ -70,7 +70,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-12: Demonstrating we’re not allowed to have
|
||||
<span class="caption">Listing 15-20: Demonstrating we’re not allowed to have
|
||||
two lists using `Box<T>` that try to share ownership of a third list</span>
|
||||
|
||||
If we compile this, we get this error:
|
||||
@@ -100,7 +100,7 @@ the list itself. The borrow checker wouldn’t let us compile `let a = Cons(10,
|
||||
`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 here in Listing 15-13. Each `Cons` variant now holds a value
|
||||
`Box<T>` as shown here in Listing 15-21. Each `Cons` variant now holds a value
|
||||
and an `Rc` pointing to a `List`. When we create `b`, instead of taking
|
||||
ownership of `a`, we clone the `Rc` that `a` is holding, which increases the
|
||||
number of references from 1 to 2 and lets `a` and `b` share ownership of the
|
||||
@@ -133,7 +133,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-13: A definition of `List` that uses
|
||||
<span class="caption">Listing 15-21: A definition of `List` that uses
|
||||
`Rc<T>`</span>
|
||||
|
||||
We need to add a `use` statement to bring `Rc` into scope because it’s not in
|
||||
@@ -154,7 +154,7 @@ memory.
|
||||
|
||||
### Cloning an `Rc<T>` Increases the Reference Count
|
||||
|
||||
Let’s change our working example from Listing 15-13 so that we can see the
|
||||
Let’s change our working example from Listing 15-21 so that we can see the
|
||||
reference counts changing as we create and drop references to the `Rc` in `a`.
|
||||
|
||||
<!-- Below -- can you let the reader know why we are doing this? What does it
|
||||
@@ -162,7 +162,7 @@ show us/improve? Is this our working version of the code, or just illustrating
|
||||
reference count? -->
|
||||
<!-- This is illustrating reference counting /Carol -->
|
||||
|
||||
In Listing 15-14, we’ll change `main` so that it has an inner scope around list
|
||||
In Listing 15-22, we’ll change `main` so that it has an inner scope around list
|
||||
`c`, so that we can see how the reference count changes when `c` goes out of
|
||||
scope. At each point in the program where the reference count changes, we’ll
|
||||
print out the reference count, which we can get by calling the
|
||||
@@ -202,7 +202,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-14: Printing out the reference count</span>
|
||||
<span class="caption">Listing 15-22: Printing out the reference count</span>
|
||||
|
||||
This will print out:
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ mechanism for sending the messages: the application could choose to put a
|
||||
message in the application, send an email, send a text message, or something
|
||||
else. Our library doesn’t need to know about that detail; all it needs is
|
||||
something that implements a trait we’ll provide called `Messenger`. Listing
|
||||
15-15 shows our library code:
|
||||
15-23 shows our library code:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
|
||||
@@ -197,7 +197,7 @@ impl<'a, T> LimitTracker<'a, T>
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-15: A library to keep track of how close to a
|
||||
<span class="caption">Listing 15-23: A library to keep track of how close to a
|
||||
maximum value a value is, and warn when the value is at certain levels</span>
|
||||
|
||||
One important part of this code is that the `Messenger` trait has one method,
|
||||
@@ -216,7 +216,7 @@ 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`, then check that the mock object has the messages we expect.
|
||||
Listing 15-16 shows an attempt of implementing a mock object to do just that,
|
||||
Listing 15-24 shows an attempt of implementing a mock object to do just that,
|
||||
but that the borrow checker won’t allow:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
@@ -254,7 +254,7 @@ mod tests {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-16: An attempt to implement a `MockMessenger`
|
||||
<span class="caption">Listing 15-24: An attempt to implement a `MockMessenger`
|
||||
that isn’t allowed by the borrow checker</span>
|
||||
|
||||
This test code defines a `MockMessenger` struct that has a `sent_messages`
|
||||
@@ -295,7 +295,7 @@ definition (feel free to try and see what error message you get).
|
||||
|
||||
This is where interior mutability can help! We’re going to store the
|
||||
`sent_messages` within a `RefCell`, and then the `send` message will be able to
|
||||
modify `sent_messages` to store the messages we’ve seen. Listing 15-17 shows
|
||||
modify `sent_messages` to store the messages we’ve seen. Listing 15-25 shows
|
||||
what that looks like:
|
||||
|
||||
<span class="filename">Filename: src/lib.rs</span>
|
||||
@@ -334,7 +334,7 @@ mod tests {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-17: Using `RefCell<T>` to be able to mutate an
|
||||
<span class="caption">Listing 15-25: Using `RefCell<T>` to be able to mutate an
|
||||
inner value while the outer value is considered immutable</span>
|
||||
|
||||
The `sent_messages` field is now of type `RefCell<Vec<String>>` instead of
|
||||
@@ -376,8 +376,8 @@ mutable borrow at any point in time.
|
||||
|
||||
If we try to violate these rules, rather than getting a compiler error like we
|
||||
would with references, the implementation of `RefCell<T>` will `panic!` at
|
||||
runtime. Listing 15-18 shows a modification to the implementation of `send`
|
||||
from Listing 15-17 where we’re deliberately trying to create two mutable
|
||||
runtime. Listing 15-26 shows a modification to the implementation of `send`
|
||||
from Listing 15-25 where we’re deliberately trying to create two mutable
|
||||
borrows active for the same scope in order to illustrate that `RefCell<T>`
|
||||
prevents us from doing this at runtime:
|
||||
|
||||
@@ -395,7 +395,7 @@ impl Messenger for MockMessenger {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-18: Creating two mutable references in the
|
||||
<span class="caption">Listing 15-26: Creating two mutable references in the
|
||||
same scope to see that `RefCell<T>` will panic</span>
|
||||
|
||||
We create a variable `one_borrow` for the `RefMut` smart pointer returned from
|
||||
@@ -439,7 +439,7 @@ For example, recall the cons list example from Listing 15-13 where we used
|
||||
`Rc<T>` to let us have multiple lists share ownership of another list. Because
|
||||
`Rc<T>` only holds immutable values, we aren’t able to change any of the values
|
||||
in the list once we’ve created them. Let’s add in `RefCell<T>` to get the
|
||||
ability to change the values in the lists. Listing 15-19 shows that by using a
|
||||
ability to change the values in the lists. Listing 15-27 shows that by using a
|
||||
`RefCell<T>` in the `Cons` definition, we’re allowed to modify the value stored
|
||||
in all the lists:
|
||||
|
||||
@@ -472,7 +472,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-19: Using `Rc<RefCell<i32>>` to create a
|
||||
<span class="caption">Listing 15-27: Using `Rc<RefCell<i32>>` to create a
|
||||
`List` that we can mutate</span>
|
||||
|
||||
We create a value that’s an instance of `Rc<RefCell<i32>` and store it in a
|
||||
|
||||
@@ -13,7 +13,7 @@ never reach 0, and the values will never be dropped.
|
||||
|
||||
Let’s take a 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-20:
|
||||
15-28:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
@@ -38,7 +38,7 @@ impl List {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-20: A cons list definition that holds a
|
||||
<span class="caption">Listing 15-28: A cons list definition that holds a
|
||||
`RefCell` so that we can modify what a `Cons` variant is referring to</span>
|
||||
|
||||
We’re using another variation of the `List` definition from Listing 15-6. The
|
||||
@@ -58,8 +58,8 @@ uses the definitions. We just broke these apart to avoid having a lot of code
|
||||
and then a lot of explanation, I'd be fine having this be one big listing if
|
||||
you think that would be better /Carol -->
|
||||
|
||||
In listing 15-21, we’re adding a `main` function that uses the definitions from
|
||||
Listing 15-20. This code creates a list in `a`, a list in `b` that points to
|
||||
In listing 15-29, we’re adding a `main` function that uses the definitions from
|
||||
Listing 15-28. This code creates a list in `a`, a list in `b` that points to
|
||||
the list in `a`, and then modifies the list in `a` to point to `b`, which
|
||||
creates a reference cycle. There are `println!` statements along the way to
|
||||
show what the reference counts are at various points in this process.
|
||||
@@ -114,7 +114,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-21: Creating a reference cycle of two `List`
|
||||
<span class="caption">Listing 15-29: Creating a reference cycle of two `List`
|
||||
values pointing to each other</span>
|
||||
|
||||
We create an `Rc` instance holding a `List` value in the variable `a` with an
|
||||
@@ -160,11 +160,11 @@ However, because `a` is still referencing the `Rc` that was in `b`, that `Rc`
|
||||
has a count of 1 rather than 0, so the memory the `Rc` has on the heap won’t be
|
||||
dropped. The memory will just sit there with a count of one, forever.
|
||||
|
||||
To visualize this, we’ve created a reference cycle that looks like Figure 15-22:
|
||||
To visualize this, we’ve created a reference cycle that looks like Figure 15-30:
|
||||
|
||||
<img alt="Reference cycle of lists" src="img/trpl15-04.svg" class="center" />
|
||||
|
||||
<span class="caption">Figure 15-22: A reference cycle of lists `a` and `b`
|
||||
<span class="caption">Figure 15-30: A reference cycle of lists `a` and `b`
|
||||
pointing to each other</span>
|
||||
|
||||
If you uncomment the last `println!` and run the program, Rust will try and
|
||||
@@ -208,7 +208,7 @@ Another solution is reorganizing your data structures so that some references
|
||||
express ownership and some references don’t. In this way, we can have cycles
|
||||
made up of some ownership relationships and some non-ownership relationships,
|
||||
and only the ownership relationships affect whether a value may be dropped or
|
||||
not. In Listing 15-20, we always want `Cons` variants to own their list, so
|
||||
not. In Listing 15-28, 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 reference cycles.
|
||||
@@ -284,7 +284,7 @@ a `RefCell` in `children` around the `Vec`.
|
||||
|
||||
Next, let’s 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-23:
|
||||
with the value 5 and `leaf` as one of its children, as shown in Listing 15-31:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
@@ -311,7 +311,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-23: Creating a `leaf` node with no children
|
||||
<span class="caption">Listing 15-31: Creating a `leaf` node with no children
|
||||
and a `branch` node with `leaf` as one of its children</span>
|
||||
|
||||
We clone the `Rc` in `leaf` and store that in `branch`, meaning the `Node` in
|
||||
@@ -365,7 +365,7 @@ you think? It seems repetitive to explain this every time. /Carol
|
||||
-->
|
||||
|
||||
This way, a node will be able to refer to its parent node, but does not own its
|
||||
parent. In Listing 15-24, let’s update `main` to use this new definition so
|
||||
parent. In Listing 15-32, let’s update `main` to use this new definition so
|
||||
that the `leaf` node will have a way to refer to its parent, `branch`:
|
||||
|
||||
<!-- Why are we updating it, what are we doing here? Can you make that clear?
|
||||
@@ -406,14 +406,14 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-24: A `leaf` node with a `Weak` reference to
|
||||
<span class="caption">Listing 15-32: A `leaf` node with a `Weak` reference to
|
||||
its parent node, `branch`</span>
|
||||
|
||||
<!-- Below: looks similar to what? What are we doing with this listing, can you
|
||||
talk it through -->
|
||||
|
||||
Creating the `leaf` node looks similar to how creating the `leaf` node looked
|
||||
in Listing 15-23, with the exception of the `parent` field: `leaf` starts out
|
||||
in Listing 15-31, with the exception of the `parent` field: `leaf` starts out
|
||||
without a parent, so we create a new, empty `Weak` reference instance.
|
||||
|
||||
At this point, when we try to get a reference to the parent of `leaf` by using
|
||||
@@ -444,7 +444,7 @@ parent? -->
|
||||
When we print out the parent of `leaf` again, this time we’ll get a `Some`
|
||||
variant holding `branch`: `leaf` can now access its parent! When we print out
|
||||
`leaf`, we also avoid the cycle that eventually ended in a stack overflow like
|
||||
we had in Listing 15-21: the `Weak` references are printed as `(Weak)`:
|
||||
we had in Listing 15-29: the `Weak` references are printed as `(Weak)`:
|
||||
|
||||
```text
|
||||
leaf parent = Some(Node { value: 5, parent: RefCell { value: (Weak) },
|
||||
@@ -462,7 +462,7 @@ Let’s look at how the `strong_count` and `weak_count` values of the `Rc`
|
||||
instances change by creating a new inner scope and moving the creation of
|
||||
`branch` into that scope. This will let us see what happens when `branch` is
|
||||
created and then dropped when it goes out of scope. The modifications are shown
|
||||
in Listing 15-25:
|
||||
in Listing 15-33:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
|
||||
@@ -510,7 +510,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 15-25: Creating `branch` in an inner scope and
|
||||
<span class="caption">Listing 15-33: Creating `branch` in an inner scope and
|
||||
examining strong and weak reference counts</span>
|
||||
|
||||
Once `leaf` is created, its `Rc` has a strong count of 1 and a weak count of 0.
|
||||
|
||||
Reference in New Issue
Block a user