Check out a free preview of the full Rust for TypeScript Developers course
The "Borrow Checker" Lesson is part of the full, Rust for TypeScript Developers course featured in this preview video. Here's what you'd learn in this lesson:
ThePrimeagen introduces the borrow checker and explains a few rules about how Rust handles values. A value can only have one owner. There can be unlimited immutable references (borrows) and only one mutable reference (if there are no immutable references).
Transcript from the "Borrow Checker" Lesson
[00:00:00]
>> I'm gonna use terms like dropped. Dropped means releasing memory. So at the end of those little squirrely brace scope that I created, the stuff inside of it was dropped. It was no longer considered valid. So there's three rules you really have to be mindful of. And these are the primary rules you'll run into mostly, at least in my opinion, in application development, which is there can be one value owner.
[00:00:21]
There can be unlimited immutable borrows, references, with no mutable borrows. There can be only one mutable borrow with no immutable borrows. Meaning you are allowed to hold on to the value, you are allowed to reference the value or you're allowed to immutably reference the value. You cannot have both reading and writing and reading going on at the same time because now you're gonna get into a weird state.
[00:00:47]
Things can happen that you may not want them to happen. And so we want it to be very careful. So one thing you can think about is that if you have any moves, if something gets moved while you have a reference, you would be referring to memory that's no longer valid.
[00:01:03]
So we have to be very careful about how that happened. So Rust just has these rules to prevent you from doing it. And as I discussed, there's all the valid safe programs and there's the ones that Rust allows. So you may see that this is safe Rust says, hey, I can't let you do that because I can't know that safe.
[00:01:19]
So it's a little different. All right, there's also a lifetime rule. A reference cannot outlive its value. In other words, we saw that one right here. So this is a lifetime one. The thing we're holding on to or the vector is referring to things longer than the things inside of it live.
[00:01:37]
It's just too long. I find that this one I don't run into too often. Again, I do mostly like little applications with it, a lot of CLI tools. I don't run into it too often. So stated differently one var owns the data, one var can change the data, many vars can look at the data, you cannot look and change simultaneously.
[00:01:57]
You cannot refer to something that has been dropped kind of like the English version of it. All right, so let's do a little bit of let's do some like little tests here to kind of play with it. So the first thing we're gonna do is we're going to create a struct called item that derives the bug I just showed you that.
[00:02:12]
I'll do it again with one property count, that's the usize. So I'm gonna go up here. Follow along, if you can. We're gonna create struct called item with a property called count that is a usize. And it's gonna implement this thing called derive debug. This may be strange terms to you, you probably have never seen that you're like, what the heck is it?
[00:02:31]
It just allows you to pretty print it. It's a macro that will change your struct and do something at compile time to allow rust to crawl its structure and maybe it stores some additional data. I don't exactly know what it does. I've never actually looked at what it expands to but I'm sure it makes perfect sense.
[00:02:49]
So there we go. Should be pretty easy to type. We got this all down. So now let's do the next part. Create a function called add_one that takes in the item and adds one to it. All right, should be pretty easy. So function add_one, we have the item that is the item.
[00:03:07]
It's gonna need to be mutable because obviously we're gonna be adding one to it. So, all right item.count+=1. There is no ++ I wish there was ++, Idabel I love ++ but you have 2+=1. It's the finer things in life that make you annoyed and this is one of them let's go back to our requirements.
[00:03:25]
In the main function create an item of type item and print it out with debug print. Okay, we can do that. So let Item= Item.count+=1. Fantastic, right? And so now we should be able to print it out with the pretty debug printing. So println and do that fun, whatever that thing is called and there you go.
[00:03:49]
This should print out our item. Beautiful. Let's go back. Let's pass the item to add_one. So we mutated and then let's print it out again, okay? Should be pretty easy add_one(item) and then we'll do the whole printing one more time. And if you've done it all correctly, you should have this incorrect program.
[00:04:14]
So, does anyone know why it errors? Take a moment and type, I'll give you a second, look at it. Would you look at it, experience it, and just try to think, why is this erroring? Because as a person who uses TypeScript, this probably is pretty frustrating looking. Like, why would this?
[00:04:36]
This is just stupid. All right, I'm gonna tell you what happened. Are you guys ready for what happened here? So first, let's look at the errors. So you get a warning right here that says, value moved here. The actual error is over here. This says, borrow of moved value item.
[00:05:00]
Well, let me ask you a question. I think I actually even have it all printed out right here. There we go. Who owns item? Let's jump back in here. Who owns item? That line owns item, right? Who owns item at this point?
>> The function add_one.
>> The function owns the item at that point, you have moved that value to the function.
[00:05:27]
You did not give it a reference, you gave it the value itself. And you can tell by the definition, it consumes the value. So we will use this word consume a bunch. That means item has been consumed and look you can even see the, look how good the errors are on this.
[00:05:45]
It even says consider changing this parameter and function to a borrow instead of owning the value. It even tells you right there, that's what the problem is. You're owning the value, you're not borrowing the value. So if we take this, change the definition to say that, we'll now get this error.
[00:06:07]
So we've made it one step further notice our borrow error has gone away because now we're passing in a reference to the item. It consumes a reference. The owner of the references now add_one, you got to think of a reference almost like a value in of itself. Same kind of concept.
[00:06:27]
But now look at this one. What's the problem here? Should be pretty straightforward. Come on I can feel you guys got it. Come on, here we go.
>> It's not mutable.
>> It's not mutable my goodness just geniuses. So there we go mute. So now we have that.
[00:06:41]
My goodness, now we have another error, what happened here? I think we can all guess what the error is. Can anyone tell me what the error is?
>> When you defined item line two of main, it wasn't mutable.
>> Correct, but that's not the issue here. Here, just looking at that, it says mutable reference, but found Immutable reference.
[00:07:05]
So we gotta change this one to mutable as well. Awesome. Now it'll error one more time and look at where the highlight error is. The highlight error tells you what you should be changing. Consider changing this to be mutable. It tells you where the problem is. You're walking the errors and the errors literally hold your hand from problem to solution all the way through.
[00:07:27]
So it's pretty cool. It's a pretty dang good compiler. I don't know if you've ever worked in C++, but that's a terrible compiler. Whereas this one, this is pretty good. This gives you pretty nice answers all the way through. Now, of course, there's some colloquialisms you have to know.
[00:07:41]
Once you start getting familiar with spotting them, it becomes excessively easy, but you just have to have this mentality of who owns the value? How long does my value live for? Long as you can ask, or long as you can answer those questions, Rust becomes easy. If you cannot answer those questions, Rust is excessively difficult.
[00:08:00]
So this is where it gets a lot of its bad name from, is this right here. All right, so, let's do this again. Let's break another rule? Yeah by the way, I forgot to ask you, what was the rule we are breaking?
>> Only one value owner.
>> Only one value owner.
[00:08:19]
We tried to have two value onwers. We had our original definition, plus the moment passed into the function, then we try to use our original definition again, can't do that. There can only be one Lord of the Ring, remember that. Was a really great reference. I feel like there's something really funny there.
[00:08:32]
I just gonna figure out how to make Frodo into a reference because he's not owner of the ring, he's just holding on to it. There's something really good about that.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops