Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions listings/ch15-smart-pointers/listing-15-03/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ enum List {
}

// ANCHOR: here
// --snip--

use crate::List::{Cons, Nil};

fn main() {
Expand Down
2 changes: 2 additions & 0 deletions listings/ch15-smart-pointers/listing-15-19/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::List::{Cons, Nil};
use std::rc::Rc;

// ANCHOR: here
// --snip--

fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
println!("count after creating a = {}", Rc::strong_count(&a));
Expand Down
378 changes: 191 additions & 187 deletions nostarch/chapter15.md

Large diffs are not rendered by default.

Binary file modified nostarch/docx/chapter15.docx
Binary file not shown.
9 changes: 1 addition & 8 deletions src/ch15-00-smart-pointers.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,6 @@ Rust, with its concept of ownership and borrowing, has an additional difference
between references and smart pointers: while references only borrow data, in
many cases smart pointers _own_ the data they point to.

Though we didn’t call them as such at the time, we’ve already encountered a few
smart pointers in this book, including `String` and `Vec<T>` in Chapter 8. Both
of these types count as smart pointers because they own some memory and allow
you to manipulate it. They also have metadata and extra capabilities or
guarantees. `String`, for example, stores its capacity as metadata and has the
extra ability to ensure its data will always be valid UTF-8.

Smart pointers are usually implemented using structs. Unlike an ordinary
struct, smart pointers implement the `Deref` and `Drop` traits. The `Deref`
trait allows an instance of the smart pointer struct to behave like a reference
Expand All @@ -48,6 +41,6 @@ cover the most common smart pointers in the standard library:

In addition, we’ll cover the _interior mutability_ pattern where an immutable
type exposes an API for mutating an interior value. We’ll also discuss
_reference cycles_: how they can leak memory and how to prevent them.
reference cycles: how they can leak memory and how to prevent them.

Let’s dive in!
26 changes: 13 additions & 13 deletions src/ch15-01-box.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
## Using `Box<T>` to Point to Data on the Heap

The most straightforward smart pointer is a _box_, whose type is written
`Box<T>`. Boxes allow you to store data on the heap rather than the stack. What
remains on the stack is the pointer to the heap data. Refer to Chapter 4 to
review the difference between the stack and the heap.
The most straightforward smart pointer is a box, whose type is written
`Box<T>`. _Boxes_ allow you to store data on the heap rather than the stack.
What remains on the stack is the pointer to the heap data. Refer to Chapter 4
to review the difference between the stack and the heap.

Boxes don’t have performance overhead, other than storing their data on the
heap instead of on the stack. But they don’t have many extra capabilities
Expand Down Expand Up @@ -54,7 +54,7 @@ Putting a single value on the heap isn’t very useful, so you won’t use boxes
themselves in this way very often. Having values like a single `i32` on the
stack, where they’re stored by default, is more appropriate in the majority of
situations. Let’s look at a case where boxes allow us to define types that we
wouldn’t be allowed to if we didn’t have boxes.
wouldn’t be allowed to define if we didn’t have boxes.

### Enabling Recursive Types with Boxes

Expand Down Expand Up @@ -136,7 +136,7 @@ is one more `Cons` value that holds `3` and a `List` value, which is finally
If we try to compile the code in Listing 15-3, we get the error shown in
Listing 15-4.

<Listing number="15-4" file-name="output.txt" caption="The error we get when attempting to define a recursive enum">
<Listing number="15-4" caption="The error we get when attempting to define a recursive enum">

```console
{{#include ../listings/ch15-smart-pointers/listing-15-03/output.txt}}
Expand Down Expand Up @@ -175,7 +175,7 @@ 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.

<img alt="An infinite Cons list" src="img/trpl15-01.svg" class="center" style="width: 50%;" />
<img alt="An infinite Cons list: a rectangle labeled 'Cons' split into two smaller rectangles. The first smaller rectangle holds the label 'i32', and the second smaller rectangle holds the label 'Cons' and a smaller version of the outer 'Cons' rectangle. The 'Cons' rectangles continue to hold smaller and smaller versions of themselves until the smallest comfortably-sized rectangle holds an infinity symbol, indicating that this repetition goes on forever" src="img/trpl15-01.svg" class="center" style="width: 50%;" />

<span class="caption">Figure 15-1: An infinite `List` consisting of infinite
`Cons` variants</span>
Expand Down Expand Up @@ -222,13 +222,13 @@ of the `List` in Listing 15-3 to the code in Listing 15-5, which will compile.

The `Cons` variant needs the size of an `i32` plus the space to store the
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
looks like now.
on the stack 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 looks like now.

<img alt="A finite Cons list" src="img/trpl15-02.svg" class="center" />
<img alt="A rectangle labeled 'Cons' split into two smaller rectangles. The first smaller rectangle holds the label 'i32', and the second smaller rectangle holds the label 'Box' with one inner rectangle that contains the label 'usize', representing the finite size of the box's pointer" src="img/trpl15-02.svg" class="center" />

<span class="caption">Figure 15-2: A `List` that is not infinitely sized
because `Cons` holds a `Box`</span>
Expand Down
20 changes: 10 additions & 10 deletions src/ch15-02-deref.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ smart pointers to work in ways similar to references. Then we’ll look at
Rust’s _deref coercion_ feature and how it lets us work with either references
or smart pointers.

> Note: There’s one big difference between the `MyBox<T>` type we’re about to
> build and the real `Box<T>`: our version will not store its data on the heap.
> We are focusing this example on `Deref`, so where the data is actually stored
> is less important than the pointer-like behavior.

<!-- Old links, do not remove -->

<a id="following-the-pointer-to-the-value-with-the-dereference-operator"></a>
Expand Down Expand Up @@ -66,7 +61,7 @@ to the value it’s pointing to.
We can rewrite the code in Listing 15-6 to use a `Box<T>` instead of a
reference; the dereference operator used on the `Box<T>` in Listing 15-7
functions in the same way as the dereference operator used on the reference in
Listing 15-6:
Listing 15-6.

<Listing number="15-7" file-name="src/main.rs" caption="Using the dereference operator on a `Box<i32>`">

Expand All @@ -81,15 +76,20 @@ The main difference between Listing 15-7 and Listing 15-6 is that here we set
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
when `y` was a reference. Next, we’ll explore what is special about `Box<T>`
that enables us to use the dereference operator by defining our own type.
that enables us to use the dereference operator by defining our own box type.

### Defining Our Own Smart Pointer

Let’s build a smart pointer similar to the `Box<T>` type provided by the
standard library to experience how smart pointers behave differently from
Let’s build a wrapper type similar to the `Box<T>` type provided by the
standard library to experience how smart pointer types behave differently from
references by default. Then we’ll look at how to add the ability to use the
dereference operator.

> Note: There’s one big difference between the `MyBox<T>` type we’re about to
> build and the real `Box<T>`: our version will not store its data on the heap.
> We are focusing this example on `Deref`, so where the data is actually stored
> is less important than the pointer-like behavior.

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
`new` function to match the `new` function defined on `Box<T>`.
Expand Down Expand Up @@ -137,7 +137,7 @@ implement the `Deref` trait.
### Implementing the `Deref` Trait

As discussed in [“Implementing a Trait on a Type”][impl-trait]<!-- ignore --> in
Chapter 10, to implement a trait, we need to provide implementations for the
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 contains an implementation
Expand Down
10 changes: 5 additions & 5 deletions src/ch15-04-rc.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Let’s return to our cons list example in 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.

<img alt="Two lists that share ownership of a third list" src="img/trpl15-03.svg" class="center" />
<img alt="A linked list with the label 'a' pointing to three elements: the first element contains the integer 5 and points to the second element. The second element contains the integer 10 and points to the third element. The third element contains the value 'Nil' that signifies the end of the list; it does not point anywhere. A linked list with the label 'b' points to an element that contains the integer 3 and points to the first element of list 'a'. A linked list with the label 'c' points to an element that contains the integer 4 and also points to the first element of list 'a', so that the tail of lists 'b' and 'c' are both list 'a'" src="img/trpl15-03.svg" class="center" />

<span class="caption">Figure 15-3: Two lists, `b` and `c`, sharing ownership of
a third list, `a`</span>
Expand All @@ -46,9 +46,9 @@ 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 number="15-17" file-name="src/main.rs" caption="Demonstrating we’re not allowed to have two lists using `Box<T>` that try to share ownership of a third list">
<Listing number="15-17" file-name="src/main.rs" caption="Demonstrating that we’re not allowed to have two lists using `Box<T>` that try to share ownership of a third list">

```rust,ignore,does_not_compile
{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-17/src/main.rs}}
Expand Down Expand Up @@ -92,8 +92,8 @@ it.
</Listing>

We need to add a `use` statement to bring `Rc<T>` into scope because it’s not
in the prelude. In `main`, we create the list holding 5 and 10 and store it in
a new `Rc<List>` in `a`. Then when we create `b` and `c`, we call the
in the prelude. In `main`, we create the list holding `5` and `10` and store it
in a new `Rc<List>` in `a`. Then, when we create `b` and `c`, we call the
`Rc::clone` function and pass a reference to the `Rc<List>` in `a` as an
argument.

Expand Down
16 changes: 8 additions & 8 deletions src/ch15-05-interior-mutability.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ beyond the scope of this book but is an interesting topic to research.
Because some analysis is impossible, if the Rust compiler can’t be sure the
code complies with the ownership rules, it might reject a correct program; in
this way, it’s conservative. If Rust accepted an incorrect program, users
wouldn’t be able to trust in the guarantees Rust makes. However, if Rust
rejects a correct program, the programmer will be inconvenienced, but nothing
wouldn’t be able to trust the guarantees Rust makes. However, if Rust rejects a
correct program, the programmer will be inconvenienced, but nothing
catastrophic can occur. The `RefCell<T>` type is useful when you’re sure your
code follows the borrowing rules but the compiler is unable to understand and
guarantee that.
Expand Down Expand Up @@ -146,7 +146,7 @@ is that we want to test the behavior of the `set_value` method on the
`set_value` doesn’t return anything for us to make assertions on. We want to be
able to say that if we create a `LimitTracker` with something that implements
the `Messenger` trait and a particular value for `max`, when we pass different
numbers for `value`, the messenger is told to send the appropriate messages.
numbers for `value` the messenger is told to send the appropriate messages.

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
Expand All @@ -173,7 +173,7 @@ take the message passed in as a parameter and store it in the `MockMessenger`
list of `sent_messages`.

In the test, we’re testing what happens when the `LimitTracker` is told to set
`value` to something that is more than 75 percent of the `max` value. First, we
`value` to something that is more than 75 percent of the `max` value. First we
create a new `MockMessenger`, which will start with an empty list of messages.
Then we create a new `LimitTracker` and give it a reference to the new
`MockMessenger` and a `max` value of `100`. We call the `set_value` method on
Expand All @@ -187,12 +187,12 @@ However, there’s one problem with this test, as shown here:
{{#include ../listings/ch15-smart-pointers/listing-15-21/output.txt}}
```

We can’t modify the `MockMessenger` to keep track of the messages, because the
We can’t modify the `MockMessenger` to keep track of the messages because the
`send` method takes an immutable reference to `self`. We also can’t take the
suggestion from the error text to use `&mut self` in both the `impl` method and
the `trait` definition. We do not want to change the `Messenger` trait solely
for the sake of testing. Instead, we need to find a way to make our test code
work correctly with our existing design.
the trait definition. We do not want to change the `Messenger` trait solely for
the sake of testing. Instead, we need to find a way to make our test code work
correctly with our existing design.

This is a situation in which interior mutability can help! We’ll store the
`sent_messages` within a `RefCell<T>`, and then the `send` method will be
Expand Down
20 changes: 10 additions & 10 deletions src/ch15-06-reference-cycles.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ The reference count of the `Rc<List>` instances in both `a` and `b` is 2 after
we change the list in `a` to point to `b`. At the end of `main`, Rust drops the
variable `b`, which decreases the reference count of the `b` `Rc<List>` instance
from 2 to 1. The memory that `Rc<List>` has on the heap won’t be dropped at
this point, because its reference count is 1, not 0. Then Rust drops `a`, which
this point because its reference count is 1, not 0. Then Rust drops `a`, which
decreases the reference count of the `a` `Rc<List>` instance from 2 to 1 as
well. This instance’s memory can’t be dropped either, because the other
`Rc<List>` instance still refers to it. The memory allocated to the list will
remain uncollected forever. To visualize this reference cycle, we’ve created the
diagram in Figure 15-4.

<img alt="Reference cycle of lists" src="img/trpl15-04.svg" class="center" />
<img alt="A rectangle labeled 'a' that points to a rectangle containing the integer 5. A rectangle labeled 'b' that points to a rectangle containing the integer 10. The rectangle containing 5 points to the rectangle containing 10, and the rectangle containing 10 points back to the rectangle containing 5, creating a cycle" src="img/trpl15-04.svg" class="center" />

<span class="caption">Figure 15-4: A reference cycle of lists `a` and `b`
pointing to each other</span>
Expand Down Expand Up @@ -115,10 +115,10 @@ reference cycles.

So far, we’ve demonstrated that calling `Rc::clone` increases the `strong_count`
of an `Rc<T>` instance, and an `Rc<T>` instance is only cleaned up if its
`strong_count` is 0. You can also create a _weak reference_ to the value within
`strong_count` is 0. You can also create a weak reference to the value within
an `Rc<T>` instance by calling `Rc::downgrade` and passing a reference to the
`Rc<T>`. Strong references are how you can share ownership of an `Rc<T>`
instance. Weak references don’t express an ownership relationship, and their
`Rc<T>`. _Strong references_ are how you can share ownership of an `Rc<T>`
instance. _Weak references_ don’t express an ownership relationship, and their
count doesn’t affect when an `Rc<T>` instance is cleaned up. They won’t cause a
reference cycle because any cycle involving some weak references will be broken
once the strong reference count of values involved is 0.
Expand Down Expand Up @@ -184,7 +184,7 @@ parent. We’ll do that next.

To make the child node aware of its parent, we need to add a `parent` field to
our `Node` struct definition. The trouble is in deciding what the type of
`parent` should be. We know it can’t contain an `Rc<T>` because that would
`parent` should be. We know it can’t contain an `Rc<T>`, because that would
create a reference cycle with `leaf.parent` pointing to `branch` and
`branch.children` pointing to `leaf`, which would cause their `strong_count`
values to never be 0.
Expand All @@ -194,7 +194,7 @@ children: if a parent node is dropped, its child nodes should be dropped as
well. However, a child should not own its parent: if we drop a child node, the
parent should still exist. This is a case for weak references!

So, instead of `Rc<T>`, we’ll make the type of `parent` use `Weak<T>`,
So instead of `Rc<T>`, we’ll make the type of `parent` use `Weak<T>`,
specifically a `RefCell<Weak<Node>>`. Now our `Node` struct definition looks
like this:

Expand All @@ -208,7 +208,7 @@ 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`
node will have a way to refer to its parent, `branch`.

<Listing number="15-28" file-name="src/main.rs" caption="A `leaf` node with a weak reference to its parent node `branch`">
<Listing number="15-28" file-name="src/main.rs" caption="A `leaf` node with a weak reference to its parent node, `branch`">

```rust
{{#rustdoc_include ../listings/ch15-smart-pointers/listing-15-28/src/main.rs:there}}
Expand All @@ -229,7 +229,7 @@ leaf parent = None
```

When we create the `branch` node, it will also have a new `Weak<Node>`
reference in the `parent` field, because `branch` doesn’t have a parent node.
reference in the `parent` field because `branch` doesn’t have a parent node.
We still have `leaf` as one of the children of `branch`. Once we have the
`Node` instance in `branch`, we can modify `leaf` to give it a `Weak<Node>`
reference to its parent. We use the `borrow_mut` method on the
Expand Down Expand Up @@ -284,7 +284,7 @@ don’t get any memory leaks!

If we try to access the parent of `leaf` after the end of the scope, we’ll get
`None` again. At the end of the program, the `Rc<Node>` in `leaf` has a strong
count of 1 and a weak count of 0, because the variable `leaf` is now the only
count of 1 and a weak count of 0 because the variable `leaf` is now the only
reference to the `Rc<Node>` again.

All of the logic that manages the counts and value dropping is built into
Expand Down