What if your program could magically keep track of who owns what, so nothing ever gets lost or misused?
Why Ownership and functions in Rust? - Purpose & Use Cases
Imagine you have a box with your favorite toy. You want to lend it to a friend to play with, but you also want to keep track of who has it so it doesn't get lost or broken.
If you just hand over the box without any rules, you might forget who has it, or both you and your friend might try to use it at the same time, causing confusion or damage.
Ownership and functions in Rust act like clear rules for lending and returning the box. They make sure only one person owns the toy at a time, and when a function uses a value, it knows exactly who is responsible for it.
fn play_with_toy(toy: String) {
println!("Playing with {}", toy);
}
let my_toy = String::from("car");
play_with_toy(my_toy);
println!("I still have my toy: {}", my_toy); // Error!fn play_with_toy(toy: String) -> String {
println!("Playing with {}", toy);
toy
}
let my_toy = String::from("car");
let my_toy = play_with_toy(my_toy);
println!("I still have my toy: {}", my_toy); // Works fineThis concept enables safe and clear management of data, preventing bugs and confusion when values move between parts of a program.
Think of a library lending books: ownership rules ensure only one person has a book at a time, and functions are like librarians who track who borrowed what and when it should be returned.
Ownership tracks who is responsible for data.
Functions can take ownership or borrow data safely.
This prevents errors like using data after it's gone.
Practice
Solution
Step 1: Understand ownership transfer in Rust functions
When a function takes ownership, it means the variable's ownership moves to the function.Step 2: Effect on original variable after function call
Since ownership moved, the original variable cannot be used anymore after the call.Final Answer:
The original variable can no longer be used after the function call. -> Option DQuick Check:
Ownership transfer = original variable unusable [OK]
- Thinking ownership is shared, not moved
- Assuming variable is copied automatically
- Confusing borrowing with ownership transfer
Solution
Step 1: Identify borrowing syntax for string slices
Borrowing a string slice uses &str type, which is a reference to a string slice.Step 2: Check each signature for borrowing without ownership
fn print_name(name: &str) { println!("{}", name); } uses &str, which borrows without taking ownership. fn print_name(name: &String) { println!("{}", name); } borrows a String reference but &str is more idiomatic for slices.Final Answer:
fn print_name(name: &str) { println!("{}", name); } -> Option CQuick Check:
Borrow string slice = &str parameter [OK]
- Using String parameter takes ownership
- Confusing &String with &str
- Returning ownership when not needed
fn take_ownership(s: String) {
println!("Inside function: {}", s);
}
fn main() {
let s = String::from("hello");
take_ownership(s);
println!("Outside function: {}", s);
}Solution
Step 1: Analyze ownership transfer in function call
The function take_ownership takes ownership of s, so s is moved into the function.Step 2: Check usage of s after function call
After the call, s is no longer valid in main, so using it causes a compile error.Final Answer:
Inside function: hello Compile error: use of moved value 's' -> Option AQuick Check:
Ownership moved, use after move = compile error [OK]
- Assuming variable is copied automatically
- Expecting output after ownership moved
- Ignoring Rust's ownership rules
fn calculate_length(s: String) -> usize {
s.len()
}
fn main() {
let s1 = String::from("hello");
let len = calculate_length(s1);
println!("The length of '{}' is {}.", s1, len);
}Solution
Step 1: Identify ownership issue in function call
calculate_length takes ownership of s1, so s1 is moved and invalid after call.Step 2: Fix by borrowing s1 instead of moving
Change function parameter to &String and pass &s1 to avoid moving ownership.Final Answer:
Error: s1 is moved into calculate_length; fix by passing &s1 instead. -> Option AQuick Check:
Pass reference to avoid moving ownership [OK]
- Trying to return reference to local variable
- Ignoring ownership move on function parameters
- Misunderstanding borrowing syntax
Solution
Step 1: Understand ownership and return requirements
The function must take ownership of the vector and return ownership back after doubling elements.Step 2: Analyze each option for ownership and functionality
fn double_vec(v: Vec<i32>) -> Vec<i32> { v.iter().map(|x| x * 2).collect() } takes ownership (Vec<i32>), creates a new doubled vector, and returns it, satisfying requirements.Final Answer:
fn double_vec(v: Vec<i32>) -> Vec<i32> { v.iter().map(|x| x * 2).collect() } -> Option BQuick Check:
Take ownership, return new doubled vector [OK]
- Borrowing vector but not returning ownership
- Not returning anything from function
- Modifying borrowed vector without ownership
Ready to prove it?
Pass the test and this pattern moves unknown
