diff --git a/nostarch/chapter15.md b/nostarch/chapter15.md index e179b1ef3..9e84ceab3 100644 --- a/nostarch/chapter15.md +++ b/nostarch/chapter15.md @@ -149,6 +149,14 @@ assume the list is the result of the function, so is a recursive list of nested pairs? /LC --> + + + For example, here's a pseudocode representation of a cons list containing the list 1, 2, 3 with each pair in parentheses: @@ -157,10 +165,6 @@ list 1, 2, 3 with each pair in parentheses: (1, (2, (3, Nil))) ``` - - - Each item in a cons list contains two elements: the value of the current item and the next item. The last item in the list contains only a value called `Nil` without a next item. A cons list is produced by recursively calling the `cons` @@ -215,8 +219,6 @@ another `Cons` value that holds `2` and another `List` value. This `List` value is one more `Cons` value that holds `3` and a `List` value, which is finally `Nil`, the non-recursive variant that signals the end of the list. - - If we try to compile the code in Listing 15-3, we get the error shown in Listing 15-4: @@ -371,11 +373,6 @@ A regular reference is a type of pointer, and one way to think of a pointer is as an arrow to a value stored somewhere else. In Listing 15-6, we create a reference to an `i32` value and then use the dereference operator to follow the reference to the value: - - Filename: src/main.rs @@ -444,14 +441,6 @@ 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` that enables us to use the dereference operator by defining our own box type. - - ### Defining Our Own Smart Pointer @@ -598,6 +587,10 @@ value as an argument to a function or method that doesn’t match the parameter type in the function or method definition. A sequence of calls to the `deref` method converts the type we provided into the type the parameter needs. + + + Deref coercion was added to Rust so that programmers writing function and method calls don’t need to add as many explicit references and dereferences with `&` and `*`. The deref coercion feature also lets us write more code that @@ -688,10 +681,6 @@ implements mutability. The first case states that if you have a `&T`, and `T` implements `Deref` to some type `U`, you can get a `&U` transparently. The second case states that the same deref coercion happens for mutable references. - - - The third case is trickier: Rust will also coerce a mutable reference to an immutable one. But the reverse is *not* possible: immutable references will never coerce to mutable references. Because of the borrowing rules, if you have @@ -710,13 +699,11 @@ The second trait important to the smart pointer pattern is `Drop`, which lets you customize what happens when a value is about to go out of scope. You can provide an implementation for the `Drop` trait on any type, and that code can be used to release resources like files or network connections. - - + We’re introducing `Drop` in the context of smart pointers because the functionality of the `Drop` trait is almost always used when implementing a smart pointer. For example, when a `Box` is dropped it will deallocate the -space on the heap that the box points to. +space on the heap that the box points to. `Drop` can of course also be used in other contexts. In some languages, for some types, the programmer must call code to free memory or resources every time they finish using an instance those types. Examples @@ -1111,12 +1098,10 @@ immutability restriction. data even when there are immutable references to that data; normally, this action is disallowed by the borrowing rules. To mutate data, the pattern uses `unsafe` code inside a data structure to bend Rust’s usual rules that govern -mutation and borrowing. We haven’t yet covered unsafe code that indicates we're -checking the rules manually instead of the compiler checking them for us; we +mutation and borrowing. Unsafe code indicates to the compiler that we're +checking the rules manually instead of relying on the compiler to check them for us; we will discuss unsafe code more in Chapter 19. - - + We can use types that use the interior mutability pattern only when we can ensure that the borrowing rules will be followed at runtime, even though the compiler can’t guarantee that. The `unsafe` code involved is then wrapped in a @@ -1222,12 +1207,6 @@ an immutable value and see why that is useful. Sometimes during testing a programmer will use a type in place of another type, in order to observe particular behavior and assert it's implemented correctly. - - This placeholder type is called a *test double*. Think of it in the sense of a "stunt double" in filmmaking, where a person steps in and substitutes for an actor to do a particular tricky scene. Test doubles stand in for other types @@ -1295,7 +1274,7 @@ where } } ``` - +' Listing 15-20: A library to keep track of how close a value is to a maximum value and warn when the value is at certain levels @@ -1601,6 +1580,11 @@ The runtime checks of the borrowing rules protect us from data races, and it’s sometimes worth trading a bit of speed for this flexibility in our data structures. + + The standard library has other types that provide interior mutability, such as `Cell`, which is similar except that instead of giving references to the inner value, the value is copied in and out of the `Cell`. There’s also @@ -1738,9 +1722,6 @@ If you uncomment the last `println!` and run the program, Rust will try to print this cycle with `a` pointing to `b` pointing to `a` and so forth until it overflows the stack. - - Compared to a real-world program, the consequences creating a reference cycle in this example aren’t very dire: right after we create the reference cycle, the program ends. However, if a more complex program allocated lots of memory @@ -1783,6 +1764,15 @@ paragraph I wasn't entirely sure. It would be good to have a high level succinct definition /LC --> + + When you call `Rc::downgrade`, you get a smart pointer of type `Weak`. Instead of increasing the `strong_count` in the `Rc` instance by 1, calling