Ownership rules help Rust keep track of who owns data to avoid bugs and crashes. They make sure memory is used safely without needing a garbage collector.
Ownership rules in Rust
let s1 = String::from("hello"); let s2 = s1; // ownership moved from s1 to s2 // s1 can no longer be used here
Ownership means one variable is responsible for a piece of data.
When ownership moves, the old owner cannot use the data anymore.
s1 to s2. Using s1 after is not allowed.let s1 = String::from("hello"); let s2 = s1; // s1 loses ownership // println!("{}", s1); // error: s1 is no longer valid
clone() makes a full copy, so both variables own their data independently.let s1 = String::from("hello"); let s2 = s1.clone(); // s1 and s2 both own separate copies println!("{}", s1); // works fine
fn take_ownership(s: String) { println!("Got: {}", s); } let s = String::from("hello"); take_ownership(s); // s can no longer be used here
& lets a function use data without taking ownership, so the original variable stays valid.fn borrow(s: &String) { println!("Borrowed: {}", s); } let s = String::from("hello"); borrow(&s); println!("Still own: {}", s);
This program shows ownership moving from s1 to s2. Then it clones s2 to s3. It also shows borrowing with a reference so ownership is not lost.
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 loses ownership
// println!("{}", s1); // error: s1 is invalid
println!("s2 owns: {}", s2);
let s3 = s2.clone(); // s2 and s3 own separate copies
println!("s2 still owns: {}", s2);
println!("s3 owns a clone: {}", s3);
borrow_string(&s3);
println!("After borrowing, s3 still owns: {}", s3);
}
fn borrow_string(s: &String) {
println!("Borrowed string: {}", s);
}Ownership rules prevent double freeing memory and dangling pointers.
Only one variable can own data at a time unless you clone it.
Borrowing lets you use data without taking ownership, but you must follow borrowing rules.
Ownership means one variable is responsible for cleaning up data.
Moving ownership invalidates the old owner.
Borrowing lets you use data temporarily without taking ownership.
Practice
Solution
Step 1: Understand ownership move
When ownership moves, the original variable loses its right to access the data.Step 2: Effect on original variable
The original variable becomes invalid and cannot be used to prevent double free errors.Final Answer:
The original variable becomes invalid and cannot be used. -> Option AQuick Check:
Ownership move invalidates old owner = A [OK]
- Thinking ownership move copies data
- Assuming both variables remain valid
- Confusing move with borrowing
Solution
Step 1: Identify borrowing syntax
Immutable borrowing uses the & symbol before the variable.Step 2: Match correct syntax
let x = &value; correctly borrows value immutably.Final Answer:
let x = &value; -> Option DQuick Check:
Immutable borrow uses & = B [OK]
- Using * for borrowing instead of dereferencing
- Missing & symbol for borrowing
- Confusing mutable and immutable borrow syntax
let s1 = String::from("hello");
let s2 = s1;
println!("{}", s1);Solution
Step 1: Analyze ownership move
Assigning s1 to s2 moves ownership, invalidating s1.Step 2: Using invalidated variable
Printing s1 after move causes a compile-time error because s1 is no longer valid.Final Answer:
Compilation error -> Option CQuick Check:
Using moved variable causes compile error = A [OK]
- Expecting s1 to print after move
- Confusing move with copy
- Thinking runtime error occurs instead
let s = String::from("hello");
let r1 = &s;
let r2 = &mut s;
println!("{} and {}", r1, r2);Solution
Step 1: Check borrowing rules
Rust forbids mutable borrow if immutable borrow exists simultaneously.Step 2: Identify conflict
r1 is an immutable borrow; r2 tries mutable borrow causing error.Final Answer:
Cannot borrow s as mutable because it is already borrowed as immutable. -> Option BQuick Check:
Mutable borrow conflicts with existing immutable borrow = D [OK]
- Ignoring borrow rules and expecting code to run
- Thinking multiple mutable borrows allowed
- Misunderstanding println! macro usage
fn take_ownership(s: String) {
println!("{}", s);
}
fn main() {
let s = String::from("hello");
take_ownership(s);
println!("{}", s);
}
What is the correct way to fix the error without cloning the string?Solution
Step 1: Understand ownership transfer
Passing s to take_ownership moves ownership, invalidating s in main.Step 2: Use borrowing to avoid move
Changing parameter to &String borrows s, so ownership stays with main.Step 3: Adjust function call
Call take_ownership(&s) to pass reference matching new parameter.Final Answer:
Change the function parameter to borrow the string: fn take_ownership(s: &String) -> Option AQuick Check:
Borrow parameter to keep ownership in caller = C [OK]
- Trying to use s after move without borrowing
- Removing code instead of fixing ownership
- Confusing mutability with ownership
Ready to prove it?
Pass the test and this pattern moves unknown
