One of the most intriguing concepts in Rust is ownership. Rather than undertaking garbage collection, Rust removes a value from memory once its owner is out of scope.
What does that mean? Well, let's talk about it.
Rust takes an alternative approach. Each value in memory is tied to an owner, which is a variable. Once that variable is no longer in scope the value is removed from memory.
Per the Rust Book, there are three rules of ownership.
- Each value in Rust has a variable that’s called its owner.
- There can only be one owner at a time.
- When the owner goes out of scope, the value will be dropped.
I've already mentioned numbers one and three. But number two is a bit more complicated.
There are two types of memory. The first, is stack memory. It's of fixed size and stored on the stack.
The second, is heap memory. Heap memory can be any size and is referenced via a pointer to that spot in memory.
There are a few things to keep in mind with this. Stack memory is "cheaper" than heap memory. It's accessed directly rather than looked up. Stack memory is also smaller than heap memory. If it can fit in a stack slot then you don't need heap memory.
So the general takeaway is that heap memory is necessary, but using stack memory is preferable when possible.
This is where ownership gets interesting. There are different rules for values stored in stack vs. heap memory.
For example, copies.
let x = 3;let y = x;
3 now appears in two stack slots, one owned by
x and one owned by
Now what happens when we deal with non-primitives? If you're familiar with deep vs. shallow copies that's a useful concept here.
let x = vec![3, 5, 7];let y = x;
This object is stored on the heap. Therefore,
x is storing a pointer to a spot in heap memory. If this were a shallow copy,
y would be pointing to the same spot.
This is a problem in Rust. Because that gives the same value in memory two owners. The cardinal rules require a single owner.
Additionally, Rust doesn't want to deep copy this object and end up with a second spot in heap memory. Instead, it ignores
x and confers
y as the owner of this value.
y goes out of scope, the object is removed from memory.
Much like the mut keyword, Rust wants you to be intentional about memory. Deep copies, or new allocations of memory, require a
let x = vec![3, 5, 7];let y = x.clone();
Otherwise, Rust will assume your last assigned variable is the owner of the value and act accordingly.
Keeping track of this as your write Rust code may seem like a lot. What happens if you want to use a value without transferring ownership? That's where references come into play. I'll get to that in my next write up.