1
00:00:01,540 --> 00:00:02,180
So far,
2
00:00:02,190 --> 00:00:04,229
we've only talked about immutably borrowing
3
00:00:04,230 --> 00:00:05,210
a value to read it.
4
00:00:05,740 --> 00:00:14,640
It's also possible to mutably borrow a value in order to change it without taking ownership. In this module, we'll show you how to create and use a mutable reference.
5
00:00:14,990 --> 00:00:16,880
We'll look at an example using a function,
6
00:00:16,950 --> 00:00:19,579
an example of a method where the first parameter is a mutable
7
00:00:19,580 --> 00:00:20,550
reference to self.
8
00:00:20,990 --> 00:00:22,580
In order to ensure memory-safety,
9
00:00:22,800 --> 00:00:24,789
the compiler enforces some rules around
10
00:00:24,790 --> 00:00:27,150
mutable references. We'll go over those.
11
00:00:27,600 --> 00:00:28,240
Lastly,
12
00:00:28,400 --> 00:00:32,180
we'll discuss an example of some code that doesn't compile because of the borrowing rules,
13
00:00:32,420 --> 00:00:40,250
and talk about the bug the compiler prevents in that situation. Let's get started with how to create and use a mutable reference.
14
00:00:41,740 --> 00:00:42,900
Recall from unit 1,
15
00:00:42,910 --> 00:00:43,700
module 3,
16
00:00:44,000 --> 00:00:45,790
that in order to make a variable mutable,
17
00:00:45,980 --> 00:00:48,350
we use the mut keyword in a let statement.
18
00:00:49,840 --> 00:00:50,630
Similarly,
19
00:00:50,680 --> 00:00:52,080
to create a mutable reference,
20
00:00:52,200 --> 00:00:54,250
we add mut after the ampersand.
21
00:00:55,820 --> 00:01:07,050
Let's look at an example of a function that needs to use mutable references. In this example, we have to find a struct named Bucket that has a liters field to store how much liquid is in the bucket.
22
00:01:08,070 --> 00:01:14,550
The [derive(Debug)] annotation on the struct definition enables us to print out the values of a Bucket for inspection later.
23
00:01:15,140 --> 00:01:21,350
We've also defined a function named pour that takes references to a source and target bucket, indicated with the ampersand.
24
00:01:22,290 --> 00:01:25,650
The function also takes an amount to transfer from the source to the target.
25
00:01:26,690 --> 00:01:34,969
The body of the function subtracts the amount from the source bucket's liters field and adds the amount to the target bucket's liters.
26
00:01:34,970 --> 00:01:35,309
In the main function, we instantiate
27
00:01:35,310 --> 00:01:41,150
two buckets and then pass references as arguments to the pour function, again, using the ampersand.
28
00:01:42,640 --> 00:01:43,750
If we compile this,
29
00:01:44,850 --> 00:01:49,550
we'll get errors that say we cannot assign to the liters field of immutable binding.
30
00:01:50,240 --> 00:01:54,220
The compiler also suggests that we change from an immutable reference to a mutable one.
31
00:01:55,840 --> 00:02:06,050
We replaced the ampersands in the definition of pour with &mut; the same replacement when we call pour and make each of the buckets mutable using the mut keyword.
32
00:02:07,440 --> 00:02:08,560
When we run this code,
33
00:02:08,750 --> 00:02:09,699
we can see that calling
34
00:02:09,700 --> 00:02:13,079
the pour function has moved three liters from Bucket 1 to Bucket 2.
35
00:02:14,940 --> 00:02:21,150
Another common way mutable references are used is as the first parameter of methods, as &mut self
36
00:02:21,540 --> 00:02:24,450
so that these methods can modify the current instance.
37
00:02:26,010 --> 00:02:28,750
We touched on this briefly in unit 1, module 9,
38
00:02:28,810 --> 00:02:30,150
but here's another example.
39
00:02:30,840 --> 00:02:34,750
We've defined a CarPool struct to model people sharing rides to work.
40
00:02:35,240 --> 00:02:36,839
The struct holds a vector of strings,
41
00:02:36,840 --> 00:02:39,950
representing the names of the passengers currently in the vehicle.
42
00:02:41,040 --> 00:02:45,920
We've defined a method named pick_up on CarPool that takes a mutable reference to itself
43
00:02:46,190 --> 00:02:49,539
so that this method can change the fields of the current CarPool
44
00:02:49,540 --> 00:02:50,200
instance.
45
00:02:51,040 --> 00:02:53,050
The method also takes the name of a passenger,
46
00:02:53,260 --> 00:02:55,399
and the body pushes the name into the passengers
47
00:02:55,400 --> 00:02:58,689
vector. In the main function, we've instantiated
48
00:02:58,690 --> 00:03:02,860
a new mutable instance of a CarPool, named monday_car_pool,
49
00:03:03,060 --> 00:03:04,650
that doesn't have any passengers.
50
00:03:05,340 --> 00:03:08,450
Then, we've called the pick_up method to add passengers to the vehicle.
51
00:03:10,440 --> 00:03:11,450
When we run this,
52
00:03:11,460 --> 00:03:13,159
we can see that the CarPool accumulates
53
00:03:13,160 --> 00:03:13,699
passengers
54
00:03:13,700 --> 00:03:15,150
as we call the pick_up method.
55
00:03:16,890 --> 00:03:18,770
Notice that because of the way methods work,
56
00:03:18,940 --> 00:03:22,350
we don't have to create a mutable reference to monday_car_pool explicitly
57
00:03:22,360 --> 00:03:23,329
with &mut
58
00:03:23,330 --> 00:03:24,250
when we call pick_up.
59
00:03:25,090 --> 00:03:27,860
Rust creates the reference automatically for the self parameter,
60
00:03:28,050 --> 00:03:29,850
and it knows to make it mutable as well.
61
00:03:31,310 --> 00:03:34,250
This may make it hard to tell which methods mutate self,
62
00:03:34,640 --> 00:03:39,450
but you can always find out by looking at the signature of the methods in the API documentation.
63
00:03:40,990 --> 00:03:44,340
The compiler enforces some rules involving mutable references.
64
00:03:44,520 --> 00:03:45,950
Let's explore those now.
65
00:03:47,480 --> 00:03:49,370
The rules are that, when you have a reference,
66
00:03:49,380 --> 00:03:55,950
you can either have any number of immutable references to a value or a single mutable reference to that value.
67
00:03:57,500 --> 00:03:59,650
To understand why these rules are necessary,
68
00:03:59,760 --> 00:04:04,310
imagine an art class where the students are painting a bowl of fruit set up in the middle of the room.
69
00:04:05,840 --> 00:04:09,850
Any number of students can look at the bowl of fruit at the same time to work on their painting.
70
00:04:10,240 --> 00:04:12,500
Because none of the students are changing the fruit setup,
71
00:04:12,620 --> 00:04:14,050
they don't interfere with each other.
72
00:04:14,440 --> 00:04:17,550
This is like having many immutable references to the same value.
73
00:04:19,040 --> 00:04:22,550
If someone comes in in the middle of a class and rearranges the fruit,
74
00:04:22,940 --> 00:04:27,550
none of the students would be able to finish their paintings because the scene they were referencing is now different.
75
00:04:28,440 --> 00:04:33,500
This is what would happen if a mutable reference was allowed at the same time that there were immutable references,
76
00:04:33,700 --> 00:04:34,850
which would cause bugs.
77
00:04:36,090 --> 00:04:41,150
Changing the fruit's position should only happen before or after class, when there are no students.
78
00:04:42,690 --> 00:04:42,919
Even
79
00:04:42,920 --> 00:04:45,080
if there weren't any students trying to paint at the time,
80
00:04:45,220 --> 00:04:48,250
if multiple people were changing the fruit setup at the same time,
81
00:04:48,570 --> 00:04:51,350
they could also conflict with each other and cause problems.
82
00:04:51,740 --> 00:04:54,750
This is why only one mutable reference is allowed at a time.
83
00:04:56,240 --> 00:04:59,090
Let's look at some code that doesn't compile because of these rules,
84
00:04:59,180 --> 00:05:01,850
to better understand the problems that Rust prevents.
85
00:05:03,340 --> 00:05:07,550
Here, we have a vector named list that contains the values 1, 2, and 3.
86
00:05:08,540 --> 00:05:13,300
We also have a for loop that iterates over the values in the list. For each value,
87
00:05:13,360 --> 00:05:18,550
the body of the loop prints out the current item and then adds to the list the current item plus one.
88
00:05:20,140 --> 00:05:23,920
If this code was allowed to compile and run, on the first iteration of the loop,
89
00:05:23,960 --> 00:05:26,049
i would be 1. The code
90
00:05:26,050 --> 00:05:29,080
would print out i is 1 and then would push 2 under the list, making the list 1, 2, 3, 2.
91
00:05:29,140 --> 00:05:36,490
Continuing to execute the code would make the vector grow continuously,
92
00:05:36,520 --> 00:05:41,210
and we'd have an infinite loop. This is likely not what we intended to happen with this code,
93
00:05:41,450 --> 00:05:43,150
but that's not even the real problem.
94
00:05:44,640 --> 00:05:47,609
Let's look at the error message the compiler gives us when we try to compile
95
00:05:47,610 --> 00:05:52,389
this code. It says, cannot borrow `list` as mutable because it is also borrowed
96
00:05:52,390 --> 00:05:53,250
as immutable.
97
00:05:54,040 --> 00:05:56,450
The immutable borrow of list occurs in the for loop,
98
00:05:56,840 --> 00:05:59,619
and the mutable borrow of list occurs when we call list.push.
99
00:05:59,620 --> 00:06:02,189
Another way
100
00:06:02,190 --> 00:06:06,090
we could have figured out that the push method takes a mutable reference to its target
101
00:06:06,190 --> 00:06:07,950
is by looking at its documentation.
102
00:06:08,370 --> 00:06:11,750
The signature shows that this method takes a mutable reference to self.
103
00:06:13,240 --> 00:06:17,110
The real problem has to do with the management of the memory backing the vector,
104
00:06:17,120 --> 00:06:18,550
which looks something like this.
105
00:06:19,440 --> 00:06:26,510
Here's the immutable borrow that the for loop takes and the mutable borrow that the push method takes. When you have a mutable borrow,
106
00:06:26,730 --> 00:06:31,350
one of the aspects of the vector's data structure that could change is the pointer to the heap data.
107
00:06:31,990 --> 00:06:34,030
If the vector has been filled to capacity,
108
00:06:34,140 --> 00:06:35,950
and we call push to add a new value,
109
00:06:36,270 --> 00:06:41,750
the implementation of push may need to allocate more memory, and change the pointer to point to the new storage location.
110
00:06:42,670 --> 00:06:43,440
At this point,
111
00:06:43,710 --> 00:06:48,150
the immutable reference that the for loop has to the vector now points to invalid memory.
112
00:06:48,840 --> 00:06:51,470
This is memory unsafety that could cause seg faults,
113
00:06:51,500 --> 00:06:58,690
but the Rust compiler prevents that. This particular bug is called iterator invalidation and is a problem in many languages,
114
00:06:58,700 --> 00:06:59,750
but not in Rust.
115
00:07:01,140 --> 00:07:04,250
We've now covered how borrowing and mutability interact.
116
00:07:04,740 --> 00:07:07,910
We've shown how to use mutable references in functions and methods.
117
00:07:08,540 --> 00:07:14,500
We've talked about the borrowing rules that say you can either have multiple immutable references or one mutable reference.
118
00:07:15,240 --> 00:07:26,390
And we've looked at an iterator invalidation bug that Rust disallows by enforcing the borrowing rules. In the next module, we'll demonstrate some common code patterns that arise due to borrowing.