My friend Malisa and I have been hacking on Servo this summer. We started from scratch, with no experience writing Rust, let alone compiled langauges. It's been challenging and fun! One of the trickier Rust concepts to understand for me was Rust's references and borrowing.
Ownership in Rust is in many ways like owning a coloring book. You can have all your friends come look at it together and flip through the pages. However, they can't color in it. This is an immutable borrow in Rust lingo.
But say you actually want to create a collective art piece with the coloring book. You can lend it to one friend at a time and tell them they can color however they want, or mutably borrow in Rust lingo. They have to give the book back to you when they're done, and you may lend it to the next friend, and so on0. If you tried to let two friends color at the same time, they can end up fighting to color the same spot.
These are the two rules of Rust's borrow system:
- If it's mutably borrowed, it must be the only borrow that currently exists.
- Otherwise, many friends can borrow immutably at the same time.
In both cases, if the lender wants to color the book, then they must get it back from the borrowers first. How else would you color a book you don't have in your hands?!
I've found that making the compilation fail, and then reading the compiler's detailed messages is a great way to learn these new concepts. Steve Klabnik, the author of "The Book", wrote an awesome introduction to Rust's borrow system, so let's mess with one of its examples, break things, and learn!
Let's start with something simple that compiles:Link to code, and its compilation message:
The compiler helpfully warns that
x didn't have to be
mutable. But why? It's because
y ends up being a separate
x is never modified in the
code. You can tell that
y are two
different things in the memory, because the printed values are
What if we didn't want to copy
and wanted changes to
y to apply to
What happened? This time,
y is not a copy
y is a reference
x, and therefore, it had to be dereferenced
before 1 is added to
y. One important thing to note is
y is an immutable reference, even
y itself is mutable! That is why the compilation
y didn't have the permission to change the value,
yet it tried to do so anyways.
Now that we know what's going on, let's fix this code and make the compiler happy again!Link to code, and its output:
y takes a mutable borrow of
x, and it
x's value. So when we print
successfully prints 6.
What happens if we try to print
x instead? This
of the Book's examples.
fails! The compiler gives a pretty good explanation. It says that
println! cannot immutably borrow
x is already mutably borrowed
y. This violates the first rule of Rust's borrow
system: when something is mutably borrowed, there cannot be other
The Book shows a way to correct this code by using curly brackets to introduce a nested scope.Link to code, and its output:
The Book does a better job in explaining scopes than I can, so I highly recommend reading the Book about this section.
Let's break this code one last time.Link to code, and its compilation message:
The compiler lets us know that
y does not exist. This is
y is defined inside the inner scope delineated by the pair of curly brackets, and outside
y doesn't exist! Introducing inner scopes gets very handy
when you want to define things only temporarily.
The Rust compiler does a great job of pointing out possible sources of error in the code. Compilation errors are not scary, and they're in fact a great conversation starter with the compiler. Try introducing different kinds of errors, and see how the compiler responds. From these conversations, I find myself learning new concepts that I didn't know before, and writing better code over time.
Now you should go break some code! Thanks for reading!
0 Or maybe you'll give the book to your friend forever, in which case you're giving away your ownership, but we won't cover that concept in this blog post.