Rust Ownership and Borrowing
Passing a value to another part of a program raises two questions: who is responsible for it, and may the original caller continue using it? Rust makes those questions part of the type-checked program.
Ownership and Moves
Each owned value has an owner, and the value is dropped when that owner leaves its scope. Assigning an owned heap-backed value such as String to another binding normally moves ownership:
let first = String::from("hello");
let second = first;
After the move, second owns the string and first cannot be used. This prevents two independent owners from trying to manage the same resource.
Borrowing
A reference borrows a value without taking ownership:
fn length(text: &String) -> usize {
text.len()
}
let text = String::from("hello");
let size = length(&text);
println!("{text} has {size} bytes");
The caller can continue using text because the function received only a shared reference.
A mutable reference permits mutation, but Rust restricts overlapping access. The practical rule is that a value may have multiple shared references or one active mutable reference, not both at the same time. This makes mutation exclusive and inspectable.
Slices
A slice is a borrowed view into a contiguous part of a collection. A string slice such as &str refers to text without owning the underlying allocation:
let text = String::from("hello");
let prefix = &text[0..2];
Because the slice borrows text, the compiler prevents the owner from being invalidated while the slice is still in use.
Reading Function Signatures
Ownership becomes easier to reason about when signatures are read as access contracts:
| Parameter shape | Typical meaning |
|---|---|
T |
The function receives the value and may take ownership. |
&T |
The function temporarily reads a borrowed value. |
&mut T |
The function temporarily has exclusive mutable access. |
The exact behavior can depend on whether a type implements copying, but this table is a useful starting model for owned data such as String and Vec<T>.