From 9eed9382a4d2fa9ccc19c8451254b9875b6da7d0 Mon Sep 17 00:00:00 2001 From: Chris Krycho Date: Mon, 30 Sep 2024 15:27:52 -0600 Subject: [PATCH] Add a short discussion of assignment and ownership in ch. 04 Add a short new section showing how assignment to a mutable variable causes an existing *owned* binding to be freed immediately. Create a new code sample and a new diagram to illustrate the behavior. Fixes #4001. --- dot/trpl04-05.dot | 85 +++++---- dot/trpl04-06.dot | 29 ++- dot/trpl04-07.dot | 41 +++++ .../Cargo.lock | 6 + .../Cargo.toml | 6 + .../src/main.rs | 8 + src/ch04-01-what-is-ownership.md | 31 ++++ src/ch04-02-references-and-borrowing.md | 6 +- src/ch04-03-slices.md | 6 +- src/img/trpl04-05.svg | 160 +++++++++-------- src/img/trpl04-06.svg | 166 ++++++++---------- src/img/trpl04-07.svg | 115 ++++++++++++ 12 files changed, 432 insertions(+), 227 deletions(-) create mode 100644 dot/trpl04-07.dot create mode 100644 listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/Cargo.lock create mode 100644 listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/Cargo.toml create mode 100644 listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/src/main.rs create mode 100644 src/img/trpl04-07.svg diff --git a/dot/trpl04-05.dot b/dot/trpl04-05.dot index ca1f7e06e9..f83ab815e0 100644 --- a/dot/trpl04-05.dot +++ b/dot/trpl04-05.dot @@ -1,32 +1,55 @@ digraph { - rankdir=LR; - overlap=false; - dpi=300.0; - node [shape="plaintext"]; - - table0[label=< - - - -
s
namevalue
ptr
>]; - table1[label=< - - - - - -
s1
namevalue
ptr
len5
capacity5
>]; - table2[label=< - - - - - - -
indexvalue
0h
1e
2l
3l
4o
>]; - - edge[tailclip="false"]; - table1:pointer:c -> table2:pointee; - table0:borrower:c -> table1:borrowee; -} - + rankdir = LR; + overlap = false; + newrank = true; + dpi = 300.0; + splines = false; + clusterrank = "local"; + node [shape = "plaintext";]; + + subgraph cluster_stack { + peripheries = 0; + rank = "same"; + + // Just to have the right height! + a [label = < + + + + + +
a
0
1
2
3
>;style = invis;]; + + s [label = < + + + + + +
s
namevalue
ptr
len4
capacity4
>;]; + } + + subgraph cluster_heap { + peripheries = 0; + rank = "same"; + + hello [label = < + + + + + + +
indexvalue
0h
1e
2l
3l
4o
>;]; + + ahoy [label = < + + + + + +
indexvalue
0a
1h
2o
3y
>;]; + } + + s -> ahoy [tailport = "pointer:c"; headport = "pointee"; tailclip = false;]; +} \ No newline at end of file diff --git a/dot/trpl04-06.dot b/dot/trpl04-06.dot index a23f179a77..ca1f7e06e9 100644 --- a/dot/trpl04-06.dot +++ b/dot/trpl04-06.dot @@ -5,37 +5,28 @@ digraph { node [shape="plaintext"]; table0[label=< - + - - +
world
s
namevalue
ptr
len5
ptr
>]; - - table3[label=< - + table1[label=<
s
+ - - - + + +
s1
namevalue
ptr
len11
capacity11
ptr
len5
capacity5
>]; - table4[label=< + table2[label=<
- - - - - -
indexvalue
0h
1e
2l
3l
4o
5
6w
7o
8r
9l
10d
>]; - edge[tailclip="false"]; - table0:pointer2:c -> table4:pointee2; - table3:pointer:c -> table4:pointee; + table1:pointer:c -> table2:pointee; + table0:borrower:c -> table1:borrowee; } diff --git a/dot/trpl04-07.dot b/dot/trpl04-07.dot new file mode 100644 index 0000000000..a23f179a77 --- /dev/null +++ b/dot/trpl04-07.dot @@ -0,0 +1,41 @@ +digraph { + rankdir=LR; + overlap=false; + dpi=300.0; + node [shape="plaintext"]; + + table0[label=< + + + + +
world
namevalue
ptr
len5
>]; + + table3[label=< + + + + + +
s
namevalue
ptr
len11
capacity11
>]; + table4[label=< + + + + + + + + + + + + +
indexvalue
0h
1e
2l
3l
4o
5
6w
7o
8r
9l
10d
>]; + + + edge[tailclip="false"]; + table0:pointer2:c -> table4:pointee2; + table3:pointer:c -> table4:pointee; +} + diff --git a/listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/Cargo.lock b/listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/Cargo.lock new file mode 100644 index 0000000000..2aa4918e5d --- /dev/null +++ b/listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/Cargo.lock @@ -0,0 +1,6 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ownership" +version = "0.1.0" + diff --git a/listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/Cargo.toml b/listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/Cargo.toml new file mode 100644 index 0000000000..e8847526dc --- /dev/null +++ b/listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ownership" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/src/main.rs b/listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/src/main.rs new file mode 100644 index 0000000000..b2d0846c11 --- /dev/null +++ b/listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/src/main.rs @@ -0,0 +1,8 @@ +fn main() { + // ANCHOR: here + let mut s = String::from("hello"); + s = String::from("ahoy"); + + println!("{s}, world!"); + // ANCHOR_END: here +} diff --git a/src/ch04-01-what-is-ownership.md b/src/ch04-01-what-is-ownership.md index b8f14fd49e..c9ff91bf21 100644 --- a/src/ch04-01-what-is-ownership.md +++ b/src/ch04-01-what-is-ownership.md @@ -356,6 +356,37 @@ In addition, there’s a design choice that’s implied by this: Rust will never automatically create “deep” copies of your data. Therefore, any *automatic* copying can be assumed to be inexpensive in terms of runtime performance. +#### Scope and Assignment + +The inverse of this is true for the relationship between scoping, ownership, and +memory being freed via the `drop` function as well. When you assign a completely +new value to an existing variable, Rust will call `drop` and free the original +value’s memory immediately. Consider this code, for example: + +```rust +{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/src/main.rs:here}} +``` + +We initially declare a variable `s` and bind it to a `String` with the value +`"hello"`. Then we immediately create a new `String` with the value `"ahoy"` and +assign it to `s`. At this point, nothing is referring to the original value on +the heap at all. + +One table s representing the string value on the stack, pointing to
+the second piece of string data (ahoy) on the heap, with the original string
+data (hello) grayed out because it cannot be accessed anymore. + +Figure 4-4: Representation in memory after `s1` has been +invalidated + +The original string thus immediately goes out of scope. Rust will run the `drop` +function on it and its memory will be freed right away. When we print the value +at the end, it will be `"ahoy, world!"`. + diff --git a/src/ch04-02-references-and-borrowing.md b/src/ch04-02-references-and-borrowing.md index 04dd601c7d..055001571a 100644 --- a/src/ch04-02-references-and-borrowing.md +++ b/src/ch04-02-references-and-borrowing.md @@ -24,13 +24,13 @@ First, notice that all the tuple code in the variable declaration and the function return value is gone. Second, note that we pass `&s1` into `calculate_length` and, in its definition, we take `&String` rather than `String`. These ampersands represent *references*, and they allow you to refer -to some value without taking ownership of it. Figure 4-5 depicts this concept. +to some value without taking ownership of it. Figure 4-6 depicts this concept. Three tables: the table for s contains only a pointer to the table
 for s1. The table for s1 contains the stack data for s1 and points to the
-string data on the heap. +string data on the heap." src="img/trpl04-06.svg" class="center" /> -Figure 4-5: A diagram of `&String s` pointing at `String +Figure 4-6: A diagram of `&String s` pointing at `String s1` > Note: The opposite of referencing by using `&` is *dereferencing*, which is diff --git a/src/ch04-03-slices.md b/src/ch04-03-slices.md index 69fb35f82d..d01d905021 100644 --- a/src/ch04-03-slices.md +++ b/src/ch04-03-slices.md @@ -119,15 +119,15 @@ corresponds to `ending_index` minus `starting_index`. So, in the case of `let world = &s[6..11];`, `world` would be a slice that contains a pointer to the byte at index 6 of `s` with a length value of `5`. -Figure 4-6 shows this in a diagram. +Figure 4-7 shows this in a diagram. Three tables: a table representing the stack data of s, which points
 to the byte at index 0 in a table of the string data "hello world" on
 the heap. The third table rep-resents the stack data of the slice world, which
 has a length value of 5 and points to byte 6 of the heap data table. +src="img/trpl04-07.svg" class="center" style="width: 50%;" /> -Figure 4-6: String slice referring to part of a +Figure 4-7: String slice referring to part of a `String` With Rust’s `..` range syntax, if you want to start at index 0, you can drop diff --git a/src/img/trpl04-05.svg b/src/img/trpl04-05.svg index b4bf2ebee8..dfe9746efd 100644 --- a/src/img/trpl04-05.svg +++ b/src/img/trpl04-05.svg @@ -1,87 +1,99 @@ - - + - -%3 - - - -table0 - -s - -name - -value - -ptr - + viewBox="0.00 0.00 1104.00 1408.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + + + +cluster_stack - - -table1 - -s1 - -name - -value - -ptr - - -len - -5 - -capacity - -5 + +cluster_heap - - -table0:c->table1:borrowee - - + + + +s + +s + +name + +value + +ptr + + +len + +4 + +capacity + +4 - - -table2 - -index - -value - -0 - -h - -1 - -e - -2 - -l - -3 - -l - -4 - -o + + +ahoy + +index + +value + +0 + +a + +1 + +h + +2 + +o + +3 + +y - + -table1:c->table2:pointee - - +s:c->ahoy:pointee + + + + + +hello + + +index + +value + +0 + +h + +1 + +e + +2 + +l + +3 + +l + +4 + +o diff --git a/src/img/trpl04-06.svg b/src/img/trpl04-06.svg index e64415fe43..b4bf2ebee8 100644 --- a/src/img/trpl04-06.svg +++ b/src/img/trpl04-06.svg @@ -5,111 +5,83 @@ --> - + viewBox="0.00 0.00 1500.00 650.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + %3 - + table0 - -world - -name - -value - -ptr - - -len - -5 + +s + +name + +value + +ptr + - - -table4 - -index - -value - -0 - -h - -1 - -e - -2 - -l - -3 - -l - -4 - -o - -5 - - - -6 - -w - -7 - -o - -8 - -r - -9 - -l - -10 - -d - - - -table0:c->table4:pointee2 - - - - + -table3 - -s - -name - -value - -ptr - - -len - -11 - -capacity - -11 +table1 + +s1 + +name + +value + +ptr + + +len + +5 + +capacity + +5 - + -table3:c->table4:pointee - - +table0:c->table1:borrowee + + + + + +table2 + +index + +value + +0 + +h + +1 + +e + +2 + +l + +3 + +l + +4 + +o + + + +table1:c->table2:pointee + + diff --git a/src/img/trpl04-07.svg b/src/img/trpl04-07.svg new file mode 100644 index 0000000000..e64415fe43 --- /dev/null +++ b/src/img/trpl04-07.svg @@ -0,0 +1,115 @@ + + + + + + +%3 + + + +table0 + +world + +name + +value + +ptr + + +len + +5 + + + +table4 + +index + +value + +0 + +h + +1 + +e + +2 + +l + +3 + +l + +4 + +o + +5 + + + +6 + +w + +7 + +o + +8 + +r + +9 + +l + +10 + +d + + + +table0:c->table4:pointee2 + + + + + +table3 + +s + +name + +value + +ptr + + +len + +11 + +capacity + +11 + + + +table3:c->table4:pointee + + + + +