Understanding ownership in Rust
Some days ago, I started learning Rust. I’m reading the official book “The Rust Programming Language” available here. When I arrived at chapter 4, I discovered how Rust manages memory and I decided to write this article to summarise what I learned.
During university, I studied mainly two programming languages: C and Java. I still have some nightmares when I think about a big project I developed in C during a course because of memory management in C.
In C, the programmer has to manually allocate and deallocate the memory while in Java, there is a garbage collector that takes care of the memory management.
Rust has a completely different way to manage memory. It is called “ownership” and it guarantees memory safety without needing a garbage collector.
This system of ownership is based on three rules:
- When we allocate some space, we will have an owner for that space;
- A value stored in a certain allocated space can be used until the owner of the space goes out of scope.
- For each allocated space, we can have one owner at a time;
Let’s see an example to have a better understanding of the first two points:
From this example we can notice some things:
- When we have to define a variable and we don’t know how much space we need at compile time, we have to allocate some space on the heap to store the value. In this case, we want to store a String, we store it on the heap and we use the method String::from(“”) to allocate space.
- We can use the variable str until the bracket is closed, then the scope is over and the variable can’t be accessed anymore.
- We don’t need to call a function to free up the memory as we do in C with free(). The memory will be automatically deallocated when the variable goes out of the scope.
Now we can consider the third rule of the ownership system: “For each allocated space we can have one owner at a time”.
To understand this rule we can consider this example:
In this snippet, we define the variable s1 and we allocate some space on the heap to store the value, then we assign s1 to s2.
In other languages, we would have behaviour like the one we show in the image. Rust does a different thing.
The rule we wrote states that each allocated space can have at most one owner at a time, in this case, if we use the approach shown in the image, we would have two variables pointing to the same address on the heap. This would be a problem because we would have two owners for that space and when we reach the end of the scope we would drop the same space twice. This is obviously a bug and Rust doesn’t like it.
To avoid this problem, Rust implemented a “Move” operation, when we assign a variable to another variable as we did in the snippet, the first variable is “de-activated” and won’t point anymore to the address on the heap while the new variable will point to the address on the heap. In this way, we can avoid the double free.