You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This contains the files for the rust course, available at https://cratecode.com/unit/xa3l5ahj5w. Learn more about creating your own lessons with the [CLI](https://github.com/Cratecode/cli) and [upload action](https://github.com/Cratecode/upload-unit).
3
+
This contains the files for the rust course, available at
4
+
https://cratecode.com/unit/xa3l5ahj5w. Learn more about creating your own
5
+
lessons with the [CLI](https://github.com/Cratecode/cli) and
In many languages, variables act like names to assign to pieces of data.
14
-
In this example, `arr` and `arr2` are both aliases that really mean the same list.
15
-
This is not how variables work in Rust.
14
+
In many languages, variables act like names to assign to pieces of data. In this
15
+
example, `arr` and `arr2` are both aliases that really mean the same list. This
16
+
is not how variables work in Rust.
16
17
17
18
## Ownership
18
19
19
-
Rust variables have the concept of "ownership".
20
-
This basically means that a variable owns a piece of data.
21
-
Another way to think about is it that a piece of data actually lives inside the variable itself.
22
-
This is a fundamental concept in Rust, so it's important to understand it.
23
-
If we wanted to write the same piece of code in Rust, it wouldn't do the same thing. If we have something like this:
20
+
Rust variables have the concept of "ownership". This basically means that a
21
+
variable owns a piece of data. Another way to think about is it that a piece of
22
+
data actually lives inside the variable itself. This is a fundamental concept in
23
+
Rust, so it's important to understand it. If we wanted to write the same piece
24
+
of code in Rust, it wouldn't do the same thing. If we have something like this:
25
+
24
26
```rust
25
27
letarr=vec![1, 2, 3];
26
28
letarr2=arr;
27
29
```
28
30
29
-
Then the data (a Vec, which is basically the same thing as an array in JavaScript and a list in other languages) is first being placed inside of `arr`, then being **moved** from `arr` to `arr2`.
30
-
After it's moved, there isn't anything in `arr`, so we can't use it.
31
+
Then the data (a Vec, which is basically the same thing as an array in
32
+
JavaScript and a list in other languages) is first being placed inside of `arr`,
33
+
then being **moved** from `arr` to `arr2`. After it's moved, there isn't
34
+
anything in `arr`, so we can't use it.
31
35
32
-
This is the core idea behind how variables work in Rust.
33
-
Instead of thinking of variables as a way to name data, think of them as the place where the data is actually stored.
34
-
If the variable no longer exists (i.e., goes out of scope), then neither does the data.
36
+
This is the core idea behind how variables work in Rust. Instead of thinking of
37
+
variables as a way to name data, think of them as the place where the data is
38
+
actually stored. If the variable no longer exists (i.e., goes out of scope),
39
+
then neither does the data.
35
40
36
41
## Borrowing
37
42
38
-
Of course, there's still a way to emulate the JavaScript code above.
39
-
We can create these sorts of "aliases" by using **references** to our variables.
40
-
These are also called **borrows** (you can think of it as borrowing the data from a variable).
41
-
It's important to consider that,
42
-
just like how Rust variables represent where the data "lives", references point to variables, not the data inside them.
43
-
If we try to move data while a reference to it exists,
44
-
we'll get compiler errors because Rust doesn't let us have a reference to something that doesn't exist
45
-
(check out the code for an example).
43
+
Of course, there's still a way to emulate the JavaScript code above. We can
44
+
create these sorts of "aliases" by using **references** to our variables. These
45
+
are also called **borrows** (you can think of it as borrowing the data from a
46
+
variable). It's important to consider that, just like how Rust variables
47
+
represent where the data "lives", references point to variables, not the data
48
+
inside them. If we try to move data while a reference to it exists, we'll get
49
+
compiler errors because Rust doesn't let us have a reference to something that
50
+
doesn't exist (check out the code for an example).
46
51
47
52
Now, let's try writing that code in Rust:
53
+
48
54
```rust
49
55
// We need to mark variables as mutable so that we can modify them.
50
56
letmutarr=vec![1, 2, 3];
@@ -68,16 +74,17 @@ let arr2 = &arr;
68
74
letmutarr3=&arr;
69
75
```
70
76
71
-
But that's about as far as we can go.
72
-
One of Rust's rules with borrows is that we can't modify data if an immutable reference to it exists.
73
-
Another big rule is that we can have one mutable reference or as many immutable references as we want, but never both.
74
-
So, we're stuck.
75
-
This is one of the things that creates the most frustration when working in Rust.
76
-
There's always a way forward, but it either requires thinking of our problem differently,
77
-
or using other tools that Rust provides us.
78
-
In most cases, we'll have to take the first option, and this case is no exception.
77
+
But that's about as far as we can go. One of Rust's rules with borrows is that
78
+
we can't modify data if an immutable reference to it exists. Another big rule is
79
+
that we can have one mutable reference or as many immutable references as we
80
+
want, but never both. So, we're stuck. This is one of the things that creates
81
+
the most frustration when working in Rust. There's always a way forward, but it
82
+
either requires thinking of our problem differently, or using other tools that
83
+
Rust provides us. In most cases, we'll have to take the first option, and this
84
+
case is no exception.
79
85
80
86
If we wanted to get the same result, we could simply use:
87
+
81
88
```rust
82
89
letmutarr=vec![1, 2, 3];
83
90
@@ -87,10 +94,10 @@ arr[0] = 1000;
87
94
println!("{arr:?} {arr:?}");
88
95
```
89
96
90
-
References are extremely useful when dealing with functions.
91
-
They let us pass our data to a function without actually giving the data to the function
92
-
(so the function "borrows" it instead).
93
-
For example:
97
+
References are extremely useful when dealing with functions. They let us pass
98
+
our data to a function without actually giving the data to the function (so the
99
+
function "borrows" it instead). For example:
100
+
94
101
```rust
95
102
// This will move `data` into `my_function_1`.
96
103
my_function_1(data);
@@ -112,20 +119,23 @@ my_function_2(&data);
112
119
113
120
### Mutable References
114
121
115
-
Mutable references are similar to normal references, but they let us modify the data that they're borrowing.
116
-
There can only ever be one mutable reference, and it can't exist if there are immutable references.
122
+
Mutable references are similar to normal references, but they let us modify the
123
+
data that they're borrowing. There can only ever be one mutable reference, and
124
+
it can't exist if there are immutable references.
117
125
118
-
In general, this is fine.
119
-
There aren't that many cases where you'd need to give away two mutable references simultaneously.
120
-
Computers run programs sequentially (one step after another), so you can just create mutable references as needed.
121
-
In fact, the place where this falls apart is with concurrent programming, where steps aren't executed one after another.
122
-
There are more language features that can be used to circumvent that, but we'll talk about those later.
126
+
In general, this is fine. There aren't that many cases where you'd need to give
127
+
away two mutable references simultaneously. Computers run programs sequentially
128
+
(one step after another), so you can just create mutable references as needed.
129
+
In fact, the place where this falls apart is with concurrent programming, where
130
+
steps aren't executed one after another. There are more language features that
131
+
can be used to circumvent that, but we'll talk about those later.
123
132
124
133
## Lifetimes
125
134
126
-
We'll go into more depth on lifetimes in the next lesson,
127
-
but the big idea behind them is that data only lives for a certain amount of time on the computer.
128
-
Take a look at this code, for example:
135
+
We'll go into more depth on lifetimes in the next lesson, but the big idea
136
+
behind them is that data only lives for a certain amount of time on the
137
+
computer. Take a look at this code, for example:
138
+
129
139
```rust
130
140
// This creates an uninitialized variable.
131
141
// Rust only allows this to exist if it's guaranteed that
@@ -140,22 +150,24 @@ let list_ref;
140
150
// can't be accessed anymore, and so are removed from memory.
141
151
{
142
152
letlist=vec![1, 2, 3];
143
-
153
+
144
154
list_ref=&list;
145
155
}
146
156
147
157
println!("{list_ref:?}");
148
158
```
149
159
150
-
This code will not work.
151
-
The issue is that we're setting `list_ref` to a reference of `list`, but `list` only exists within that block.
152
-
As soon as it isn't accessible anymore, it'll get removed from memory,
153
-
so the `println`wouldn't have anything to access.
160
+
This code will not work. The issue is that we're setting `list_ref` to a
161
+
reference of `list`, but `list` only exists within that block. As soon as it
162
+
isn't accessible anymore, it'll get removed from memory, so the `println`
163
+
wouldn't have anything to access.
154
164
155
165
In some languages, doing something like this might lead to undefined behavior.
156
-
Our reference would still point to a place in memory (specifically, the point that the Vec used to take up),
157
-
but that memory could contain anything at all when we print it.
158
-
Because this leads to undefined behavior, Rust gives us an error:
166
+
Our reference would still point to a place in memory (specifically, the point
167
+
that the Vec used to take up), but that memory could contain anything at all
168
+
when we print it. Because this leads to undefined behavior, Rust gives us an
169
+
error:
170
+
159
171
```rust
160
172
error[E0597]: `list` doesnotlivelongenough
161
173
-->src/main.rs:16:16
@@ -169,19 +181,18 @@ error[E0597]: `list` does not live long enough
169
181
|--------borrowlaterusedhere
170
182
```
171
183
172
-
This is the basic idea behind lifetimes.
173
-
Data only lives for a certain amount of time,
174
-
and if references outlive the things they point to, issues start to creep up.
175
-
To fix this, we would need to make `list` live longer.
176
-
An easy way to do that is to move it into a variable that lives longer:
184
+
This is the basic idea behind lifetimes. Data only lives for a certain amount of
185
+
time, and if references outlive the things they point to, issues start to creep
186
+
up. To fix this, we would need to make `list` live longer. An easy way to do
187
+
that is to move it into a variable that lives longer:
177
188
178
189
```rust
179
190
letnew_list;
180
191
letlist_ref;
181
192
182
193
{
183
194
letlist=vec![1, 2, 3];
184
-
195
+
185
196
// It needs to be done in this order because
186
197
// of our rules with moving while we have a reference.
187
198
new_list=list;
@@ -191,6 +202,5 @@ let list_ref;
191
202
println!("{list_ref:?}");
192
203
```
193
204
194
-
Alternatively, we could just remove the scope.
195
-
There are also nicer ways to do things like this, which we'll look into soon.
196
-
Happy coding!
205
+
Alternatively, we could just remove the scope. There are also nicer ways to do
206
+
things like this, which we'll look into soon. Happy coding!
0 commit comments