Rust Ownership
Understanding Rust's memory management system
🔐 What is Ownership?
Ownership is Rust's unique system for managing memory safely without garbage collection. Each value has a single owner, and when the owner goes out of scope, the value is automatically cleaned up, preventing memory leaks and dangling pointers.
fn main() {
let s1 = String::from("hello"); // s1 owns the string
let s2 = s1; // ownership moves to s2
// println!("{}", s1); // Error! s1 no longer owns the value
println!("{}", s2); // This works
}
Output:
hello
Ownership Rules
Single Owner
Each value has exactly one owner
let x = String::from("hello");
Move Semantics
Ownership can be transferred (moved)
let y = x; // ownership moves
Automatic Cleanup
Memory freed when owner goes out of scope
} // x is dropped here
No Double Free
Prevents memory safety issues
// Compile-time safety
🔹 Ownership Transfer (Move)
When you assign a value to another variable, ownership moves:
fn main() {
// Ownership with heap data
let s1 = String::from("hello");
let s2 = s1; // s1's ownership moves to s2
println!("{}", s2); // Works
// println!("{}", s1); // Error: s1 no longer valid
// Stack data is copied, not moved
let x = 5;
let y = x; // x is copied to y
println!("x: {}, y: {}", x, y); // Both work
}
Output:
hello
x: 5, y: 5
🔹 Functions and Ownership
Passing values to functions also transfers ownership:
fn main() {
let s = String::from("hello");
takes_ownership(s); // s's ownership moves into function
// println!("{}", s); // Error: s no longer valid
let x = 5;
makes_copy(x); // x is copied, still valid
println!("x is still: {}", x); // This works
}
fn takes_ownership(some_string: String) {
println!("{}", some_string);
} // some_string goes out of scope and is dropped
fn makes_copy(some_integer: i32) {
println!("{}", some_integer);
} // some_integer goes out of scope, nothing special happens
Output:
hello
5
x is still: 5
🔹 Returning Values and Ownership
Functions can return ownership to the caller:
fn main() {
let s1 = gives_ownership(); // Function returns ownership
let s2 = String::from("hello"); // s2 comes into scope
let s3 = takes_and_gives_back(s2); // s2 moves in, s3 gets ownership
println!("s1: {}", s1);
println!("s3: {}", s3);
// s2 is no longer valid here
}
fn gives_ownership() -> String {
let some_string = String::from("yours");
some_string // Return ownership to caller
}
fn takes_and_gives_back(a_string: String) -> String {
a_string // Return ownership to caller
}
Output:
s1: yours
s3: hello
🔹 Clone for Deep Copy
Use clone() to create a deep copy instead of moving:
fn main() {
let s1 = String::from("hello");
let s2 = s1.clone(); // Deep copy, both s1 and s2 are valid
println!("s1: {}, s2: {}", s1, s2);
// Both variables can be used
let len1 = s1.len();
let len2 = s2.len();
println!("Lengths: {} and {}", len1, len2);
}
Output:
s1: hello, s2: hello
Lengths: 5 and 5