1
00:00:01,730 --> 00:00:03,809
In the last module, we had a working solution
2
00:00:04,009 --> 00:00:05,340
to the pluralize exercise
3
00:00:05,660 --> 00:00:07,859
that cloned the string passed to the pluralize
4
00:00:08,059 --> 00:00:08,370
function.
5
00:00:09,070 --> 00:00:10,830
This allowed the pluralize function to take
6
00:00:11,030 --> 00:00:12,340
ownership of the cloned value
7
00:00:12,660 --> 00:00:14,490
while the original value could still be used
8
00:00:14,690 --> 00:00:15,510
in the main function.
9
00:00:17,120 --> 00:00:18,990
However, having the pluralize function
10
00:00:19,190 --> 00:00:20,849
take an owned string value isn't the
11
00:00:21,049 --> 00:00:22,260
most idiomatic solution.
12
00:00:23,010 --> 00:00:25,049
The most idiomatic solution uses the Rust
13
00:00:25,249 --> 00:00:26,520
feature called borrowing.
14
00:00:28,060 --> 00:00:28,760
In this module,
15
00:00:28,960 --> 00:00:30,490
we'll talk about what borrowing is
16
00:00:30,690 --> 00:00:32,380
and reasons your code might want to borrow
17
00:00:32,580 --> 00:00:33,670
instead of taking ownership.
18
00:00:34,530 --> 00:00:36,519
Borrowing a value may feel similar to using
19
00:00:36,719 --> 00:00:37,699
a pointer if you're familiar
20
00:00:37,899 --> 00:00:39,190
with languages that use pointers.
21
00:00:39,460 --> 00:00:41,529
But there are important differences in Rust
22
00:00:41,729 --> 00:00:42,340
that we'll go over.
23
00:00:43,370 --> 00:00:45,500
Finally, we'll update the pluralize function
24
00:00:45,700 --> 00:00:47,390
to borrow instead of taking ownership,
25
00:00:47,770 --> 00:00:49,670
and we'll talk about why it's more idiomatic.
26
00:00:51,220 --> 00:00:52,930
So, what is borrowing?
27
00:00:54,410 --> 00:00:56,450
Borrowing is a way to allow some code
28
00:00:56,650 --> 00:00:58,640
to use a value without moving ownership.
29
00:00:59,420 --> 00:01:01,429
It's like letting someone borrow one of your toys
30
00:01:01,629 --> 00:01:02,010
for a little while.
31
00:01:04,450 --> 00:01:06,370
Even though someone else is using your toy,
32
00:01:06,580 --> 00:01:07,360
you still own it,
33
00:01:07,560 --> 00:01:09,369
and it's still your responsibility to clean
34
00:01:09,569 --> 00:01:10,780
it up when everyone's done.
35
00:01:13,890 --> 00:01:15,470
Let's look at an example in code.
36
00:01:16,200 --> 00:01:18,480
We have a Person struct that has a name field.
37
00:01:19,050 --> 00:01:20,970
We also have a function called congratulate,
38
00:01:21,330 --> 00:01:23,190
which takes a person as a parameter.
39
00:01:24,090 --> 00:01:26,009
Since the congratulate function doesn't need
40
00:01:26,209 --> 00:01:27,510
to have ownership of the person,
41
00:01:27,750 --> 00:01:30,059
it borrows the person, which is indicated
42
00:01:30,259 --> 00:01:32,190
by the ampersand before the type name.
43
00:01:33,330 --> 00:01:34,010
In main,
44
00:01:34,290 --> 00:01:36,240
we first create an instance of a Person,
45
00:01:36,540 --> 00:01:38,360
and then we call the congratulate function
46
00:01:38,560 --> 00:01:40,229
and pass it a reference to the Person
47
00:01:40,429 --> 00:01:41,580
instance as an argument.
48
00:01:42,240 --> 00:01:44,159
We create the reference by again using an
49
00:01:44,359 --> 00:01:44,790
ampersand.
50
00:01:46,060 --> 00:01:48,350
p retains ownership of the Person instance;
51
00:01:48,730 --> 00:01:50,020
we can still use it in main,
52
00:01:50,260 --> 00:01:52,149
we didn't have to clone it, and it gets
53
00:01:52,349 --> 00:01:53,460
cleaned up at the end of main
54
00:01:53,660 --> 00:01:55,470
when p goes out of scope - not in
55
00:01:55,670 --> 00:01:56,620
the congratulate function.
56
00:01:58,190 --> 00:02:00,050
This code compiles without any errors
57
00:02:00,250 --> 00:02:01,880
and prints both the congratulations
58
00:02:02,080 --> 00:02:03,620
and the message at the end of main.
59
00:02:05,270 --> 00:02:06,560
So, why would we want to borrow?
60
00:02:08,120 --> 00:02:10,038
The reason we want the ability to borrow is
61
00:02:10,238 --> 00:02:10,970
for performance.
62
00:02:11,510 --> 00:02:13,329
If a function doesn't need ownership of
63
00:02:13,529 --> 00:02:15,020
a value that has allocated memory,
64
00:02:15,470 --> 00:02:17,359
instead of cloning the value and giving that to the
65
00:02:17,559 --> 00:02:17,810
function,
66
00:02:18,200 --> 00:02:20,089
we can give the function a reference to the original
67
00:02:20,289 --> 00:02:20,390
value.
68
00:02:21,030 --> 00:02:22,610
The function can borrow the value
69
00:02:22,810 --> 00:02:24,360
and no extra allocation is needed.
70
00:02:26,020 --> 00:02:27,969
For example, pretend that the Person struct
71
00:02:28,169 --> 00:02:29,750
had 10 fields and the congratulate
72
00:02:29,950 --> 00:02:31,720
function only needed to use one of them.
73
00:02:32,270 --> 00:02:34,170
If we had to clone the whole Person instance
74
00:02:34,370 --> 00:02:36,090
in order to pass it to a function that only uses
75
00:02:36,290 --> 00:02:36,760
part of it,
76
00:02:37,210 --> 00:02:39,099
we would be wasting the memory space needed to
77
00:02:39,299 --> 00:02:40,959
store the cloned instance, and we'd
78
00:02:41,159 --> 00:02:42,640
be wasting time making the clone.
79
00:02:43,330 --> 00:02:44,050
With borrowing,
80
00:02:44,260 --> 00:02:46,110
no cloning of anything is necessary.
81
00:02:47,700 --> 00:02:49,810
Borrowing is also a signal of intent.
82
00:02:50,400 --> 00:02:52,860
When you look at a function signature in the documentation
83
00:02:53,130 --> 00:02:54,690
and see that it borrows its parameters,
84
00:02:55,050 --> 00:02:56,309
you know it wants nothing to do
85
00:02:56,509 --> 00:02:57,179
with the allocation
86
00:02:57,379 --> 00:02:58,860
or deallocation of that data.
87
00:03:00,360 --> 00:03:02,229
Borrowing and references may remind you
88
00:03:02,429 --> 00:03:03,909
of pointers in languages like C
89
00:03:04,109 --> 00:03:06,219
and C++. References
90
00:03:06,419 --> 00:03:07,180
in Rust are similar -
91
00:03:07,450 --> 00:03:09,580
there is one big, important difference.
92
00:03:11,030 --> 00:03:13,009
In safe Rust, the borrow checker
93
00:03:13,209 --> 00:03:14,670
ensures, at compile time,
94
00:03:14,970 --> 00:03:17,070
that you'll never have an invalid reference -
95
00:03:17,270 --> 00:03:18,870
a reference that points to nothing
96
00:03:19,070 --> 00:03:20,130
or to invalid memory.
97
00:03:20,550 --> 00:03:22,350
This prevents a lot of bugs.
98
00:03:23,910 --> 00:03:25,739
For example, here are some bugs you may have
99
00:03:25,939 --> 00:03:27,120
seen in other languages.
100
00:03:27,790 --> 00:03:29,580
If you've ever gotten a seg fault in C
101
00:03:29,780 --> 00:03:30,660
or C++,
102
00:03:30,860 --> 00:03:32,669
or errors like undefined method for nil
103
00:03:32,869 --> 00:03:33,570
class in Ruby,
104
00:03:33,770 --> 00:03:35,910
or undefined is not a function in JavaScript,
105
00:03:36,240 --> 00:03:38,159
you've experienced a runtime bug caused
106
00:03:38,359 --> 00:03:39,330
by an invalid reference
107
00:03:39,540 --> 00:03:41,400
that's a compile time error in Rust.
108
00:03:42,170 --> 00:03:44,009
These runtime errors happen only in certain
109
00:03:44,209 --> 00:03:44,880
circumstances
110
00:03:45,090 --> 00:03:46,620
and can be very hard to track down.
111
00:03:47,250 --> 00:03:49,260
Rust catches these errors every time
112
00:03:49,500 --> 00:03:51,359
and won't let you try to even run code
113
00:03:51,559 --> 00:03:52,080
with this problem.
114
00:03:53,010 --> 00:03:54,810
Let's see what happens when we try to create
115
00:03:55,010 --> 00:03:56,070
an invalid reference.
116
00:03:56,700 --> 00:03:58,410
You may think that this code should work.
117
00:03:58,610 --> 00:03:59,910
If so, don't feel bad -
118
00:04:00,240 --> 00:04:02,100
lots of people think that this code should work.
119
00:04:03,000 --> 00:04:05,430
The function name doesn't take any arguments.
120
00:04:05,630 --> 00:04:07,579
It allocates a new String and attempts
121
00:04:07,779 --> 00:04:09,270
to return a reference to that String.
122
00:04:10,930 --> 00:04:13,170
When we try to compile this, we get an error saying
123
00:04:13,370 --> 00:04:14,910
missing lifetime specifier.
124
00:04:15,340 --> 00:04:17,219
We're going to talk all about lifetimes in unit
125
00:04:17,419 --> 00:04:19,109
4. But for now, trust
126
00:04:19,309 --> 00:04:21,119
me that adding a lifetime specifier here won't
127
00:04:21,319 --> 00:04:21,930
fix the problem.
128
00:04:22,650 --> 00:04:24,270
The help text gives more of a hint:
129
00:04:24,780 --> 00:04:26,609
this function's return type contains
130
00:04:26,809 --> 00:04:27,450
a borrowed value,
131
00:04:27,720 --> 00:04:30,030
but there is no value for it to be borrowed from.
132
00:04:31,620 --> 00:04:32,790
Looking at the code again,
133
00:04:32,990 --> 00:04:34,829
the problem is that the variable n is
134
00:04:35,029 --> 00:04:36,530
the owner of the allocated String.
135
00:04:36,960 --> 00:04:39,119
But n goes out of scope at the end of the name
136
00:04:39,319 --> 00:04:40,969
function. Rust
137
00:04:41,169 --> 00:04:42,830
doesn't let us return a reference to n
138
00:04:43,030 --> 00:04:44,779
from this function because there's nothing for
139
00:04:44,979 --> 00:04:46,040
that reference to point to
140
00:04:46,240 --> 00:04:47,330
once the function is over.
141
00:04:48,050 --> 00:04:49,879
If we were able to do this, the
142
00:04:50,079 --> 00:04:51,800
variable my_name in main
143
00:04:52,010 --> 00:04:53,690
would contain an invalid reference.
144
00:04:55,220 --> 00:04:57,290
In general, you can't return a reference
145
00:04:57,490 --> 00:04:59,269
from a function that points to something that
146
00:04:59,469 --> 00:05:00,980
was created within that function -
147
00:05:01,300 --> 00:05:02,329
n will go out of scope
148
00:05:02,529 --> 00:05:04,120
and get cleaned up at the end of the function.
149
00:05:05,530 --> 00:05:06,430
To fix this code,
150
00:05:06,700 --> 00:05:08,470
change the name function to return an
151
00:05:08,670 --> 00:05:10,379
owned String instead of a borrowed
152
00:05:10,579 --> 00:05:11,290
string slice
153
00:05:11,490 --> 00:05:12,850
and return the String directly.
154
00:05:13,510 --> 00:05:15,400
This way, ownership is returned
155
00:05:15,600 --> 00:05:16,360
out of the function
156
00:05:16,560 --> 00:05:17,830
and the String doesn't get cleaned up.
157
00:05:19,560 --> 00:05:21,600
Now, let's take this knowledge about borrowing
158
00:05:21,800 --> 00:05:23,880
and apply it to the pluralize exercise.
159
00:05:25,380 --> 00:05:27,479
Here's the first solution we went over in the previous
160
00:05:27,679 --> 00:05:29,400
module, where we cloned s
161
00:05:29,600 --> 00:05:31,529
and passed the cloned value to the pluralize
162
00:05:31,729 --> 00:05:32,090
function.
163
00:05:33,780 --> 00:05:35,380
Instead of cloning s in main,
164
00:05:35,680 --> 00:05:37,630
we're going to pass a borrowed string slice
165
00:05:37,830 --> 00:05:39,490
of s to pluralize.
166
00:05:40,430 --> 00:05:42,260
This means we have to change the signature
167
00:05:42,460 --> 00:05:44,170
of pluralize to expect a string
168
00:05:44,370 --> 00:05:46,220
slice as the type of the singular argument.
169
00:05:47,240 --> 00:05:48,910
We'll talk about why this is &str,
170
00:05:49,110 --> 00:05:50,750
a string slice,
171
00:05:51,260 --> 00:05:53,089
rather than &String, in
172
00:05:53,289 --> 00:05:53,840
the next module.
173
00:05:55,400 --> 00:05:57,560
If we compile at this point, we'll get an error
174
00:05:57,760 --> 00:05:59,690
because we need to fix the body of pluralize.
175
00:06:00,130 --> 00:06:01,969
The error message tells us we can't use the
176
00:06:02,169 --> 00:06:03,830
plus operator to concatenate
177
00:06:04,030 --> 00:06:05,030
two string slices.
178
00:06:05,810 --> 00:06:07,700
The help text explains more about why.
179
00:06:08,240 --> 00:06:10,069
The plus operator puts the result of
180
00:06:10,269 --> 00:06:11,929
the concatenation into the string on
181
00:06:12,129 --> 00:06:13,910
the left. So, the string on the left
182
00:06:14,180 --> 00:06:16,099
needs to be able to be reallocated to
183
00:06:16,299 --> 00:06:17,600
make more space for the result.
184
00:06:18,110 --> 00:06:19,640
String slices are borrowed
185
00:06:19,840 --> 00:06:20,990
and can't reallocate.
186
00:06:21,750 --> 00:06:22,340
The help text
187
00:06:22,540 --> 00:06:23,930
also tells us how to fix this
188
00:06:24,260 --> 00:06:25,069
by adding to_owned()
189
00:06:25,269 --> 00:06:26,480
to create a String.
190
00:06:27,170 --> 00:06:28,670
This does allocate memory.
191
00:06:30,280 --> 00:06:31,240
Let's make that change
192
00:06:31,440 --> 00:06:32,980
and call to_owned on singular.
193
00:06:34,930 --> 00:06:36,189
Now the solution compiles
194
00:06:36,389 --> 00:06:38,400
and runs, producing the output we expect.
195
00:06:39,860 --> 00:06:41,870
In this case, changing to borrowing
196
00:06:42,070 --> 00:06:43,820
isn't about saving an allocation,
197
00:06:44,060 --> 00:06:45,920
as we're still needing to make that allocation
198
00:06:46,120 --> 00:06:47,899
for the new String created from the concate
199
00:06:48,099 --> 00:06:48,370
nation.
200
00:06:49,220 --> 00:06:51,289
We still think that borrowing is a more idiomatic
201
00:06:51,489 --> 00:06:53,300
solution than the solution where we cloned
202
00:06:53,500 --> 00:06:54,200
s in main.
203
00:06:54,800 --> 00:06:57,229
Here, the allocation is an implementation
204
00:06:57,429 --> 00:06:59,329
detail encapsulated in the pluralize
205
00:06:59,529 --> 00:07:01,300
function rather than making that
206
00:07:01,500 --> 00:07:03,080
a concern of the code calling
207
00:07:03,280 --> 00:07:04,000
pluralize.
208
00:07:05,560 --> 00:07:07,389
We've shown that borrowing is a way to lend
209
00:07:07,589 --> 00:07:08,120
out a value,
210
00:07:08,320 --> 00:07:10,209
instead of transferring ownership to allow
211
00:07:10,409 --> 00:07:11,800
other code to use the value.
212
00:07:13,010 --> 00:07:15,070
Rust code uses borrowing to reduce
213
00:07:15,270 --> 00:07:17,259
allocations, which can improve the runtime
214
00:07:17,459 --> 00:07:19,290
performance and memory usage of our code.
215
00:07:20,460 --> 00:07:22,660
Borrowing in Rust is less error-prone
216
00:07:22,860 --> 00:07:24,400
than using pointers in other languages
217
00:07:24,640 --> 00:07:26,559
because Rust makes sure that the references are
218
00:07:26,759 --> 00:07:28,539
always valid. In
219
00:07:28,739 --> 00:07:30,470
general, having functions borrow
220
00:07:30,670 --> 00:07:32,409
values rather than take ownership is
221
00:07:32,609 --> 00:07:33,340
more idiomatic.
222
00:07:35,120 --> 00:07:36,770
These are the basics about borrowing.
223
00:07:36,970 --> 00:07:38,809
There are more details that we're going to get into
224
00:07:39,009 --> 00:07:39,610
in the next module.