1.9.1. The Core Idea of Ownership
The core idea of Rust’s memory model is that every value has exactly one owner. In other words, only one place — usually a scope — is responsible for freeing each value.
This behavior is enforced by the borrow checker. If a value is moved — for example by assigning it to a new variable, pushing it into a Vec, placing it on the heap, and so on — then the owner becomes the new location.
The owner is really just a location in memory; the place where the data lives is the value’s owner. A move means the data is transferred from one location to another, and the new location becomes the owner.
However, some types do not follow this rule: if a value’s type implements the Copy trait, then reassignment performs a copy rather than a move. That is, a copy of the value is placed in the new location.
1.9.2. How to Implement the Copy Trait
Types that implement Copy must be able to duplicate their values bit by bit.
Types that cannot implement Copy naturally include:
- Types that contain non-
Copytypes - Types that must perform special resource-release work when their values are dropped
Why?
Imagine Box<T> implemented Copy. If you assigned box1 = box2, then both variables would believe they owned a heap allocation that belonged exclusively to them. When they went out of scope, both would try to free that memory, causing a double free.
1.9.3. Dropping Values
When a value is no longer needed, its owner deletes it.
Dropping — or discarding — a value happens when it goes out of scope. Types recursively drop the values they contain. For example, deleting a complex type can require deleting many values.
Rust does not drop the same value more than once because of ownership. If a variable contains references to other values that it does not own, then deleting that variable does not delete the other values.
That may be hard to understand, so let’s look at a simple example:
fn main() {
let x1 = 42;
let y1 = Box::new(x1);
{
let z = (x1, y1);
}
let x2 = x1;
}
Enter fullscreen mode Exit fullscreen mode
-
x1is ani32, andy1is aBox<i32>that owns a heap allocation containing a copy ofx1’s value (becausei32isCopy,Box::new(x1)does not borrowx1) -
{}creates a new scope, andzis created inside that smaller scope -
zis a tuple whose value is(x1, y1).x1is ani32and implementsCopy, sox1copies its value intoz;y1is aBox<i32>and does not implementCopy, so it cannot be copied and instead transfers ownership toz - After leaving the inner scope,
x1is used again.x1is still valid because it copied its value intozand remains usable itself -
y1becomes invalid after being assigned tozbecause ownership moved toz
1.9.4. The Order of Dropping Values
- Variables, including function parameters, are dropped in reverse order of declaration.
- Nested values are dropped in source order. In the example above, when the inner scope ends,
zis dropped: it first drops its first element (the copiedi32), then its second element (theBox). Becausey1was moved intoz,y1itself is not dropped again afterward.
Note: Rust does not currently allow self-referential values inside a single value.
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.