Skip to content

Commit 11fdeab

Browse files
authored
Merge pull request #29 from edilmedeiros/edilmedeiros-chap9_01
Edit Chapter 9.01
2 parents 1bdc969 + 3152086 commit 11fdeab

File tree

1 file changed

+54
-17
lines changed

1 file changed

+54
-17
lines changed

Diff for: 09_01_shared_references.md

+54-17
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
# Shared References
22

3-
In addition to a *mutable* reference, as indicated by the `&mut` keyword, we can also pass around a *shared* reference to a variable, which can be done by simply prefacing a variable with the `&` symbol. A mutable reference can modify the underlying data where as the shared reference cannot and is read-only. We already saw an example of a shared reference in chapter 6 where we created a slice reference to data on the heap by prepending `[u8]` with the `&` symbol.
3+
In addition to a *mutable* reference, as indicated by the `&mut` keyword, we can also pass around a *shared* reference to a variable, which can be done by simply prefacing a variable with the `&` symbol.
4+
A mutable reference can modify the underlying data where as the shared reference cannot and is read-only.
5+
We already saw an example of a shared reference in chapter 6 where we created a slice reference to data on the heap by prepending `[u8]` with the `&` symbol.
46

5-
A reference is a kind of pointer. It points to some data elsewhere and "borrows" it instead of "owns" it. What does this mean? Well let's see with an [example](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#references-and-borrowing):
7+
A reference is a kind of pointer.
8+
It points to some data elsewhere and "borrows" it instead of "owning" it.
9+
What does this mean?
10+
Well let's see with an [example](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#references-and-borrowing):
611

712
```rust
813
fn main() {
@@ -18,7 +23,8 @@ fn calculate_length(s: String) -> usize {
1823
}
1924
```
2025

21-
You can run this code online with [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=cf786ab3bacd43e260e73ae5efa49d50). If you run it, you'll notice that there will be a compiler error:
26+
You can run this code online with [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=cf786ab3bacd43e260e73ae5efa49d50).
27+
If you run it, you'll notice that there will be a compiler error:
2228
```console
2329
Compiling playground v0.0.1 (/playground)
2430
error[E0382]: borrow of moved value: `s1`
@@ -34,13 +40,25 @@ error[E0382]: borrow of moved value: `s1`
3440
| ^^ value borrowed here after move
3541
```
3642

37-
The error points out that a move occurs and that we are unable to "borrow" the value after a move. It also mentions that the type, `String` does not implement the `Copy` trait.
43+
The error points out that a move occurs and that we are unable to "borrow" the value after a move.
44+
It also mentions that the type, `String` does not implement the `Copy` trait.
3845

39-
By default, any type that does not implement the `Copy` trait will get "moved" when passed as an argument. This means the variable that contains it will no longer be available within the scope of original function. It's "ownership" is now passed to the function being called, which in this case is `calculate_length`. Why does Rust do this? Well this has to do with how Rust handles memory management internally. This way, it's always clear which variable "owns" data so that when that variable goes out of scope, the memory associated with it can be automatically freed. This is different from how other languages handle memory with garbage collection or reference counting to know when memory should be freed.
46+
By default, any type that does not implement the `Copy` trait will get "moved" when passed as an argument.
47+
This means the variable that contains it will no longer be available within the scope of original function.
48+
It's "ownership" is now passed to the function being called, which in this case is `calculate_length`.
4049

41-
So if we want to keep referring to the string after it has been passed to the `calculate_length` function, we need to use a *reference*. The reference will "borrow" the value and won't actually "own" the underlying data. This means that when the reference goes out of scope and is no longer in use, the heap data and its owner will still remain.
50+
Why does Rust do this?
51+
Well this has to do with how Rust handles memory management internally.
52+
This way, it's always clear which variable "owns" data so that when that variable goes out of scope, the memory associated with it can be automatically freed.
53+
This is different from how other languages handle memory with garbage collection or reference counting to know when memory should be freed.
4254

43-
We can create a reference by placing the `&` symbol in front and modifying the function argument type:
55+
Since `s1` was moved to the scope of `calculate_length`, the `String` data will be deallocated when the function returns.
56+
That's why we can't print it when we are back in `main`, the data would not exist anymore.
57+
If we want to keep referring to the string after it has been passed to the `calculate_length` function, we need to pass a *reference* as argument instead.
58+
The reference will "borrow" the value and won't actually "own" the underlying data.
59+
This means that when the reference goes out of scope and is no longer in use, the heap data and its owner will still remain.
60+
61+
We can create a reference by placing the `&` symbol in front of an identifier and modifying the function argument type:
4462

4563
```rust
4664
fn main() {
@@ -61,7 +79,10 @@ This will work now and correctly print:
6179
The length of 'hello' is 5.
6280
```
6381

64-
`s1` remains the owner of the String. `s` in the `calculate_length` will merely borrow a shared, immutable reference to the String. This means that we wouldn't be able to mutate the String in `calculate_length`. For example this won't work,
82+
`s1` remains the owner of the String.
83+
`s` in the `calculate_length` will merely borrow a shared, immutable reference to the String.
84+
This means that we wouldn't be able to mutate the String in `calculate_length`.
85+
For example this won't work,
6586

6687
```rust
6788
fn main() {
@@ -118,7 +139,8 @@ The length of 'hell' is 4.
118139

119140
That's the basics of shared and mutable references!
120141

121-
It's important to point out here that there is an exception to this rule, which we alluded to earlier and that is any type that implements the `Copy` trait, such as an integer type or an array `[u8; N]`. Typically, these are types that are stack allocated and don't require any heap allocations.
142+
It's important to point out here that there is an exception to this rule, which we alluded to earlier and that is any type that implements the `Copy` trait, such as an integer type or an array `[u8; N]`.
143+
Typically, these are types that are stack allocated and don't require any heap allocations.
122144

123145
Let's take a look at an example (see [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=bbc4ad315069566df4b5d853280492d1)):
124146

@@ -135,10 +157,13 @@ fn calculate_len(mut arr: [u8; 4]) -> usize {
135157
}
136158
```
137159

138-
This will run just fine without needing to pass a shared reference. Why? Because a copy will automatically be made in the `calculate_len` function and Rust won't have to worry about or think about ownership of data on the heap.
160+
This will run just fine without needing to pass a shared reference.
161+
Why? Because a copy will automatically be made in the `calculate_len` function and Rust won't have to worry about or think about ownership of data on the heap.
139162

140163
### Single Writer or Multiple Readers
141-
Rust enforces a simple, yet important rule when it comes to passing references and that is single writer OR multiple readers. In other words, you can have many different immutable, shared references to an object OR you can have just one mutable reference at any given time. You can't have both a shared reference and a mutable reference at the same time.
164+
Rust enforces a simple, yet important rule when it comes to passing references and that is single writer OR multiple readers.
165+
In other words, you can have many different immutable, shared references to an object OR you can have just one mutable reference at any given time.
166+
You can't have both a shared reference and a mutable reference at the same time.
142167

143168
Let's walk through an example to see why:
144169

@@ -150,9 +175,11 @@ fn main() {
150175
r[0] // r still points to v, which doesn't point to anything and so is a dangling pointer
151176
}
152177
```
153-
The statement `let aside = v` *moves* the vec from `v` into `aside`. However, `r` still references the variable `v` which is now uninitialized.
178+
The statement `let aside = v` *moves* the vec from `v` into `aside`.
179+
However, `r` still references the variable `v` which is now uninitialized.
154180

155-
If we have a shared reference to some variable and that variable goes out of scope or becomes uninitialized, we would end up with a dangling pointer. This can lead to unexpected behavior in a program and so Rust will attempt to avoid these possibilities.
181+
If we have a shared reference to some variable and that variable goes out of scope or becomes uninitialized, we would end up with a dangling pointer.
182+
This can lead to unexpected behavior in a program and so Rust will attempt to avoid these possibilities.
156183

157184
This is what the compiler will complain:
158185
```console
@@ -168,14 +195,24 @@ error[E0505]: cannot move out of `v` because it is borrowed
168195
17 | r[0]; // r still points to v, which doesn't point to anything and so is a dangling pointer
169196
| - borrow later used here
170197
```
171-
In other words, Rust will complain and enforce the rule that we cannot make any changes to `v` while it is being borrowed as an immutable, shared reference. This will prevent a case of a dangling pointer.
198+
In other words, Rust will complain and enforce the rule that we cannot make any changes to `v` while it is being borrowed as an immutable, shared reference.
199+
This will prevent a case of a dangling pointer.
172200

173-
You may see this compiler error from time to time. Just remember the rule: you can only have a single writer (mutable reference) OR multiple readers (shared references).
201+
You may see this compiler error from time to time.
202+
Just remember the rule: you can only have a single writer (mutable reference) OR multiple readers (shared references).
174203

175-
Ok! That's it for references! Take a breather as you just got past one of the hardest aspects of understanding the Rust programmming language. Don't worry if it hasn't fully "sunk in" yet. This is something that takes time and practice to get familiar with. Just know that with time these concepts will make more sense and you might even begin to start appreciating them.
204+
Ok! That's it for references!
205+
Take a breather as you just got past one of the hardest aspects of understanding the Rust programmming language.
206+
Don't worry if it hasn't fully "sunk in" yet.
207+
This is something that takes time and practice to get familiar with.
208+
Just know that with time these concepts will make more sense and you might even begin to start appreciating them.
176209

177210
### Quiz
178-
*What do you think would happen if we attempted to modify the vector in our project while we have a slice that borrows a reference to it? Experiment by calling `.clear()` on the vector (after declaring it mutable). See example below. Run it and see what happens. Can you explain why the compiler is returning an error and the meaning of that error?*
211+
*What do you think would happen if we attempted to modify the vector in our project while we have a slice that borrows a reference to it?
212+
Experiment by calling `.clear()` on the vector (after declaring it mutable).
213+
See example below.
214+
Run it and see what happens.
215+
Can you explain why the compiler is returning an error and the meaning of that error?*
179216
```rust
180217
fn main() {
181218
let transaction_hex = "010000000242d5c1d6f7308bbe95c0f6e1301dd73a8da77d2155b0773bc297ac47f9cd7380010000006a4730440220771361aae55e84496b9e7b06e0a53dd122a1425f85840af7a52b20fa329816070220221dd92132e82ef9c133cb1a106b64893892a11acf2cfa1adb7698dcdc02f01b0121030077be25dc482e7f4abad60115416881fe4ef98af33c924cd8b20ca4e57e8bd5feffffff75c87cc5f3150eefc1c04c0246e7e0b370e64b17d6226c44b333a6f4ca14b49c000000006b483045022100e0d85fece671d367c8d442a96230954cdda4b9cf95e9edc763616d05d93e944302202330d520408d909575c5f6976cc405b3042673b601f4f2140b2e4d447e671c47012103c43afccd37aae7107f5a43f5b7b223d034e7583b77c8cd1084d86895a7341abffeffffff02ebb10f00000000001976a9144ef88a0b04e3ad6d1888da4be260d6735e0d308488ac508c1e000000000017a91476c0c8f2fc403c5edaea365f6a284317b9cdf7258700000000";

0 commit comments

Comments
 (0)