Skip to content

Commit dc67ffe

Browse files
committed
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.
1 parent 09239f3 commit dc67ffe

File tree

12 files changed

+432
-227
lines changed

12 files changed

+432
-227
lines changed

dot/trpl04-05.dot

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,55 @@
11
digraph {
2-
rankdir=LR;
3-
overlap=false;
4-
dpi=300.0;
5-
node [shape="plaintext"];
6-
7-
table0[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
8-
<TR><TD COLSPAN="2" SIDES="B">s</TD></TR>
9-
<TR><TD>name</TD><TD>value</TD></TR>
10-
<TR><TD>ptr</TD><TD PORT="borrower"></TD></TR>
11-
</TABLE>>];
12-
table1[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
13-
<TR><TD COLSPAN="2" SIDES="B">s1</TD></TR>
14-
<TR><TD>name</TD><TD>value</TD></TR>
15-
<TR><TD PORT="borrowee">ptr</TD><TD PORT="pointer"></TD></TR>
16-
<TR><TD>len</TD><TD>5</TD></TR>
17-
<TR><TD>capacity</TD><TD>5</TD></TR>
18-
</TABLE>>];
19-
table2[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
20-
<TR><TD>index</TD><TD>value</TD></TR>
21-
<TR><TD PORT="pointee">0</TD><TD>h</TD></TR>
22-
<TR><TD>1</TD><TD>e</TD></TR>
23-
<TR><TD>2</TD><TD>l</TD></TR>
24-
<TR><TD>3</TD><TD>l</TD></TR>
25-
<TR><TD>4</TD><TD>o</TD></TR>
26-
</TABLE>>];
27-
28-
edge[tailclip="false"];
29-
table1:pointer:c -> table2:pointee;
30-
table0:borrower:c -> table1:borrowee;
31-
}
32-
2+
rankdir = LR;
3+
overlap = false;
4+
newrank = true;
5+
dpi = 300.0;
6+
splines = false;
7+
clusterrank = "local";
8+
node [shape = "plaintext";];
9+
10+
subgraph cluster_stack {
11+
peripheries = 0;
12+
rank = "same";
13+
14+
// Just to have the right height!
15+
a [label = <<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" BGCOLOR="gray">
16+
<TR><TD>a</TD></TR>
17+
<TR><TD>0</TD></TR>
18+
<TR><TD>1</TD></TR>
19+
<TR><TD>2</TD></TR>
20+
<TR><TD>3</TD></TR>
21+
</TABLE>>;style = invis;];
22+
23+
s [label = <<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
24+
<TR><TD COLSPAN="2" SIDES="B">s</TD></TR>
25+
<TR><TD>name</TD><TD>value</TD></TR>
26+
<TR><TD>ptr</TD><TD PORT="pointer"></TD></TR>
27+
<TR><TD>len</TD><TD>4</TD></TR>
28+
<TR><TD>capacity</TD><TD>4</TD></TR>
29+
</TABLE>>;];
30+
}
31+
32+
subgraph cluster_heap {
33+
peripheries = 0;
34+
rank = "same";
35+
36+
hello [label = <<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" BGCOLOR="gray">
37+
<TR><TD>index</TD><TD>value</TD></TR>
38+
<TR><TD PORT="pointee">0</TD><TD>h</TD></TR>
39+
<TR><TD>1</TD><TD>e</TD></TR>
40+
<TR><TD>2</TD><TD>l</TD></TR>
41+
<TR><TD>3</TD><TD>l</TD></TR>
42+
<TR><TD>4</TD><TD>o</TD></TR>
43+
</TABLE>>;];
44+
45+
ahoy [label = <<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
46+
<TR><TD>index</TD><TD>value</TD></TR>
47+
<TR><TD PORT="pointee">0</TD><TD>a</TD></TR>
48+
<TR><TD>1</TD><TD>h</TD></TR>
49+
<TR><TD>2</TD><TD>o</TD></TR>
50+
<TR><TD>3</TD><TD>y</TD></TR>
51+
</TABLE>>;];
52+
}
53+
54+
s -> ahoy [tailport = "pointer:c"; headport = "pointee"; tailclip = false;];
55+
}

dot/trpl04-06.dot

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,28 @@ digraph {
55
node [shape="plaintext"];
66

77
table0[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
8-
<TR><TD COLSPAN="2" SIDES="B">world</TD></TR>
8+
<TR><TD COLSPAN="2" SIDES="B">s</TD></TR>
99
<TR><TD>name</TD><TD>value</TD></TR>
10-
<TR><TD>ptr</TD><TD PORT="pointer2"></TD></TR>
11-
<TR><TD>len</TD><TD>5</TD></TR>
10+
<TR><TD>ptr</TD><TD PORT="borrower"></TD></TR>
1211
</TABLE>>];
13-
14-
table3[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
15-
<TR><TD COLSPAN="2" SIDES="B">s</TD></TR>
12+
table1[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
13+
<TR><TD COLSPAN="2" SIDES="B">s1</TD></TR>
1614
<TR><TD>name</TD><TD>value</TD></TR>
17-
<TR><TD>ptr</TD><TD PORT="pointer"></TD></TR>
18-
<TR><TD>len</TD><TD>11</TD></TR>
19-
<TR><TD>capacity</TD><TD>11</TD></TR>
15+
<TR><TD PORT="borrowee">ptr</TD><TD PORT="pointer"></TD></TR>
16+
<TR><TD>len</TD><TD>5</TD></TR>
17+
<TR><TD>capacity</TD><TD>5</TD></TR>
2018
</TABLE>>];
21-
table4[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
19+
table2[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
2220
<TR><TD>index</TD><TD>value</TD></TR>
2321
<TR><TD PORT="pointee">0</TD><TD>h</TD></TR>
2422
<TR><TD>1</TD><TD>e</TD></TR>
2523
<TR><TD>2</TD><TD>l</TD></TR>
2624
<TR><TD>3</TD><TD>l</TD></TR>
2725
<TR><TD>4</TD><TD>o</TD></TR>
28-
<TR><TD>5</TD><TD> </TD></TR>
29-
<TR><TD PORT="pointee2">6</TD><TD>w</TD></TR>
30-
<TR><TD>7</TD><TD>o</TD></TR>
31-
<TR><TD>8</TD><TD>r</TD></TR>
32-
<TR><TD>9</TD><TD>l</TD></TR>
33-
<TR><TD>10</TD><TD>d</TD></TR>
3426
</TABLE>>];
3527

36-
3728
edge[tailclip="false"];
38-
table0:pointer2:c -> table4:pointee2;
39-
table3:pointer:c -> table4:pointee;
29+
table1:pointer:c -> table2:pointee;
30+
table0:borrower:c -> table1:borrowee;
4031
}
4132

dot/trpl04-07.dot

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
digraph {
2+
rankdir=LR;
3+
overlap=false;
4+
dpi=300.0;
5+
node [shape="plaintext"];
6+
7+
table0[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
8+
<TR><TD COLSPAN="2" SIDES="B">world</TD></TR>
9+
<TR><TD>name</TD><TD>value</TD></TR>
10+
<TR><TD>ptr</TD><TD PORT="pointer2"></TD></TR>
11+
<TR><TD>len</TD><TD>5</TD></TR>
12+
</TABLE>>];
13+
14+
table3[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
15+
<TR><TD COLSPAN="2" SIDES="B">s</TD></TR>
16+
<TR><TD>name</TD><TD>value</TD></TR>
17+
<TR><TD>ptr</TD><TD PORT="pointer"></TD></TR>
18+
<TR><TD>len</TD><TD>11</TD></TR>
19+
<TR><TD>capacity</TD><TD>11</TD></TR>
20+
</TABLE>>];
21+
table4[label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
22+
<TR><TD>index</TD><TD>value</TD></TR>
23+
<TR><TD PORT="pointee">0</TD><TD>h</TD></TR>
24+
<TR><TD>1</TD><TD>e</TD></TR>
25+
<TR><TD>2</TD><TD>l</TD></TR>
26+
<TR><TD>3</TD><TD>l</TD></TR>
27+
<TR><TD>4</TD><TD>o</TD></TR>
28+
<TR><TD>5</TD><TD> </TD></TR>
29+
<TR><TD PORT="pointee2">6</TD><TD>w</TD></TR>
30+
<TR><TD>7</TD><TD>o</TD></TR>
31+
<TR><TD>8</TD><TD>r</TD></TR>
32+
<TR><TD>9</TD><TD>l</TD></TR>
33+
<TR><TD>10</TD><TD>d</TD></TR>
34+
</TABLE>>];
35+
36+
37+
edge[tailclip="false"];
38+
table0:pointer2:c -> table4:pointee2;
39+
table3:pointer:c -> table4:pointee;
40+
}
41+

listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/Cargo.lock

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "ownership"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
// ANCHOR: here
3+
let mut s = String::from("hello");
4+
s = String::from("ahoy");
5+
6+
println!("{s}, world!");
7+
// ANCHOR_END: here
8+
}

src/ch04-01-what-is-ownership.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,37 @@ In addition, there’s a design choice that’s implied by this: Rust will never
356356
automatically create “deep” copies of your data. Therefore, any *automatic*
357357
copying can be assumed to be inexpensive in terms of runtime performance.
358358

359+
#### Scope and Assignment
360+
361+
The inverse of this is true for the relationship between scoping, ownership, and
362+
memory being freed via the `drop` function as well. When you assign a completely
363+
new value to an existing variable, Rust will call `drop` and free the original
364+
value’s memory immediately. Consider this code, for example:
365+
366+
```rust
367+
{{#rustdoc_include ../listings/ch04-understanding-ownership/no-listing-04b-replacement-drop/src/main.rs:here}}
368+
```
369+
370+
We initially declare a variable `s` and bind it to a `String` with the value
371+
`"hello"`. Then we immediately create a new `String` with the value `"ahoy"` and
372+
assign it to `s`. At this point, nothing is referring to the original value on
373+
the heap at all.
374+
375+
<img alt="One table s representing the string value on the stack, pointing to
376+
the second piece of string data (ahoy) on the heap, with the original string
377+
data (hello) grayed out because it cannot be accessed anymore."
378+
src="img/trpl04-05.svg"
379+
class="center"
380+
style="width: 50%;"
381+
/>
382+
383+
<span class="caption">Figure 4-5: Representation in memory after the initial
384+
value has been replaced in its entirety.</span>
385+
386+
The original string thus immediately goes out of scope. Rust will run the `drop`
387+
function on it and its memory will be freed right away. When we print the value
388+
at the end, it will be `"ahoy, world!"`.
389+
359390
<!-- Old heading. Do not remove or links may break. -->
360391
<a id="ways-variables-and-data-interact-clone"></a>
361392

src/ch04-02-references-and-borrowing.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ First, notice that all the tuple code in the variable declaration and the
2424
function return value is gone. Second, note that we pass `&s1` into
2525
`calculate_length` and, in its definition, we take `&String` rather than
2626
`String`. These ampersands represent *references*, and they allow you to refer
27-
to some value without taking ownership of it. Figure 4-5 depicts this concept.
27+
to some value without taking ownership of it. Figure 4-6 depicts this concept.
2828

2929
<img alt="Three tables: the table for s contains only a pointer to the table
3030
for s1. The table for s1 contains the stack data for s1 and points to the
31-
string data on the heap." src="img/trpl04-05.svg" class="center" />
31+
string data on the heap." src="img/trpl04-06.svg" class="center" />
3232

33-
<span class="caption">Figure 4-5: A diagram of `&String s` pointing at `String
33+
<span class="caption">Figure 4-6: A diagram of `&String s` pointing at `String
3434
s1`</span>
3535

3636
> Note: The opposite of referencing by using `&` is *dereferencing*, which is

src/ch04-03-slices.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,15 @@ corresponds to `ending_index` minus `starting_index`. So, in the case of `let
119119
world = &s[6..11];`, `world` would be a slice that contains a pointer to the
120120
byte at index 6 of `s` with a length value of `5`.
121121

122-
Figure 4-6 shows this in a diagram.
122+
Figure 4-7 shows this in a diagram.
123123

124124
<img alt="Three tables: a table representing the stack data of s, which points
125125
to the byte at index 0 in a table of the string data &quot;hello world&quot; on
126126
the heap. The third table rep-resents the stack data of the slice world, which
127127
has a length value of 5 and points to byte 6 of the heap data table."
128-
src="img/trpl04-06.svg" class="center" style="width: 50%;" />
128+
src="img/trpl04-07.svg" class="center" style="width: 50%;" />
129129

130-
<span class="caption">Figure 4-6: String slice referring to part of a
130+
<span class="caption">Figure 4-7: String slice referring to part of a
131131
`String`</span>
132132

133133
With Rust’s `..` range syntax, if you want to start at index 0, you can drop

0 commit comments

Comments
 (0)