Ownership helps Rust keep track of who owns data. Functions can take or give ownership to keep programs safe and fast.
Ownership and functions in Rust
fn function_name(parameter: Type) -> ReturnType {
// function body
}Parameters can take ownership or borrow data using references.
Functions can return ownership by returning values.
fn take_ownership(s: String) { println!("{}", s); } fn main() { let s = String::from("hello"); take_ownership(s); // s is no longer valid here }
fn borrow_string(s: &String) { println!("{}", s); } fn main() { let s = String::from("hello"); borrow_string(&s); // s can still be used here println!("Still can use s: {}", s); }
fn give_ownership() -> String { let s = String::from("hello"); s } fn main() { let s1 = give_ownership(); println!("{}", s1); }
This program shows two functions: one takes ownership of a string, the other borrows it. After ownership is taken, the original variable cannot be used. After borrowing, it can still be used.
fn main() {
let s = String::from("Rust");
print_string(s);
// s is no longer valid here
let s2 = String::from("Ownership");
print_string_borrow(&s2);
println!("After borrowing: {}", s2);
}
fn print_string(s: String) {
println!("Owned string: {}", s);
}
fn print_string_borrow(s: &String) {
println!("Borrowed string: {}", s);
}When a function takes ownership, the original variable can no longer be used after the call.
Borrowing with references lets you use data without giving up ownership.
Returning a value from a function transfers ownership to the caller.
Functions can take or borrow ownership of data.
Ownership rules help prevent bugs and keep programs safe.
Understanding ownership with functions is key to writing Rust code.
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
