Bird
Raised Fist0
Rustprogramming~20 mins

Ownership and functions in Rust - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Rust Ownership Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
What is the output of this Rust code involving ownership and function calls?

Consider the following Rust code. What will be printed when it runs?

Rust
fn take_ownership(s: String) {
    println!("Inside function: {}", s);
}

fn main() {
    let s = String::from("hello");
    take_ownership(s);
    // println!("Outside function: {}", s); // What happens if uncommented?
}
AInside function: hello
B
Inside function: hello
Outside function: hello
CCompilation error: use of moved value 's'
DRuntime error: use of invalid memory
Attempts:
2 left
💡 Hint

Think about what happens to ownership of s when passed to the function.

❓ Predict Output
intermediate
2:00remaining
What is the output when borrowing a value in a function?

Look at this Rust code. What will it print?

Rust
fn borrow_string(s: &String) {
    println!("Inside function: {}", s);
}

fn main() {
    let s = String::from("world");
    borrow_string(&s);
    println!("Outside function: {}", s);
}
ARuntime error: use of moved value
B
Inside function: world
Outside function: world
CCompilation error: cannot borrow 's' as immutable because it is also borrowed as mutable
DInside function: world
Attempts:
2 left
💡 Hint

Consider how borrowing works in Rust and whether ownership moves.

🔧 Debug
advanced
2:00remaining
What error does this Rust code produce related to ownership?

Examine the code below. What error will the Rust compiler report?

Rust
fn main() {
    let s1 = String::from("hello");
    let s2 = s1;
    println!("{}", s1);
}
Aerror: expected `String`, found `&str`
Berror: cannot assign twice to immutable variable `s1`
Cerror: use of moved value: `s1`
Derror: mismatched types in assignment
Attempts:
2 left
💡 Hint

Think about what happens when you assign s1 to s2.

📝 Syntax
advanced
2:00remaining
Which function signature correctly takes ownership of a vector and returns its length?

Choose the correct Rust function signature that takes ownership of a Vec and returns its length as usize.

Afn vec_length(v: &mut Vec<i32>) -> usize { v.len() }
Bfn vec_length(v: &Vec<i32>) -> usize { v.len() }
Cfn vec_length(v: Vec<i32>) { v.len() }
Dfn vec_length(v: Vec<i32>) -> usize { v.len() }
Attempts:
2 left
💡 Hint

Focus on ownership transfer and return type.

🚀 Application
expert
3:00remaining
What is the value of `result` after this ownership and function call sequence?

Analyze the following Rust code. What is the value of result after main runs?

Rust
fn consume_and_return(s: String) -> String {
    let mut new_s = s;
    new_s.push_str(" world");
    new_s
}

fn main() {
    let s1 = String::from("hello");
    let result = consume_and_return(s1);
    // println!("{}", s1); // Would cause error
}
A"hello world"
B"hello"
CCompilation error: use of moved value 's1'
D" world"
Attempts:
2 left
💡 Hint

Consider how ownership moves and what the function returns.

Practice

(1/5)
1. What happens when a function in Rust takes ownership of a variable passed to it?
easy
A. The variable is shared between the function and the caller simultaneously.
B. The variable is copied and both original and function have ownership.
C. The function borrows the variable temporarily without taking ownership.
D. The original variable can no longer be used after the function call.

Solution

  1. Step 1: Understand ownership transfer in Rust functions

    When a function takes ownership, it means the variable's ownership moves to the function.
  2. Step 2: Effect on original variable after function call

    Since ownership moved, the original variable cannot be used anymore after the call.
  3. Final Answer:

    The original variable can no longer be used after the function call. -> Option D
  4. Quick Check:

    Ownership transfer = original variable unusable [OK]
Hint: Ownership moves to function, original variable becomes invalid [OK]
Common Mistakes:
  • Thinking ownership is shared, not moved
  • Assuming variable is copied automatically
  • Confusing borrowing with ownership transfer
2. Which of the following function signatures correctly borrows a string slice without taking ownership?
easy
A. fn print_name(name: String) { println!("{}", name); }
B. fn print_name(name: &String) { println!("{}", name); }
C. fn print_name(name: &str) { println!("{}", name); }
D. fn print_name(name: String) -> String { name }

Solution

  1. Step 1: Identify borrowing syntax for string slices

    Borrowing a string slice uses &str type, which is a reference to a string slice.
  2. 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.
  3. Final Answer:

    fn print_name(name: &str) { println!("{}", name); } -> Option C
  4. Quick Check:

    Borrow string slice = &str parameter [OK]
Hint: Use &str to borrow string slices without ownership [OK]
Common Mistakes:
  • Using String parameter takes ownership
  • Confusing &String with &str
  • Returning ownership when not needed
3. What will be the output of this Rust code?
fn take_ownership(s: String) {
    println!("Inside function: {}", s);
}

fn main() {
    let s = String::from("hello");
    take_ownership(s);
    println!("Outside function: {}", s);
}
medium
A. Inside function: hello Compile error: use of moved value 's'
B. Inside function: hello Outside function: hello
C. Inside function: hello Outside function: <empty>
D. Runtime error: variable s not found

Solution

  1. Step 1: Analyze ownership transfer in function call

    The function take_ownership takes ownership of s, so s is moved into the function.
  2. 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.
  3. Final Answer:

    Inside function: hello Compile error: use of moved value 's' -> Option A
  4. Quick Check:

    Ownership moved, use after move = compile error [OK]
Hint: Using moved variable after function call causes compile error [OK]
Common Mistakes:
  • Assuming variable is copied automatically
  • Expecting output after ownership moved
  • Ignoring Rust's ownership rules
4. Identify the error in this Rust code and how to fix it:
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);
}
medium
A. Error: s1 is moved into calculate_length; fix by passing &s1 instead.
B. Error: calculate_length returns wrong type; fix by returning &usize.
C. Error: println! macro syntax incorrect; fix by removing quotes.
D. No error; code runs and prints length correctly.

Solution

  1. Step 1: Identify ownership issue in function call

    calculate_length takes ownership of s1, so s1 is moved and invalid after call.
  2. Step 2: Fix by borrowing s1 instead of moving

    Change function parameter to &String and pass &s1 to avoid moving ownership.
  3. Final Answer:

    Error: s1 is moved into calculate_length; fix by passing &s1 instead. -> Option A
  4. Quick Check:

    Pass reference to avoid moving ownership [OK]
Hint: Pass references to keep ownership when calling functions [OK]
Common Mistakes:
  • Trying to return reference to local variable
  • Ignoring ownership move on function parameters
  • Misunderstanding borrowing syntax
5. You want to write a function that takes ownership of a vector, doubles each element, and returns ownership back. Which function signature and body correctly implement this in Rust?
hard
A. fn double_vec(v: &Vec<i32>) -> Vec<i32> { v.iter().map(|x| x * 2).collect() }
B. fn double_vec(v: Vec<i32>) -> Vec<i32> { v.iter().map(|x| x * 2).collect() }
C. fn double_vec(v: Vec<i32>) { for x in &v { println!("{}", x * 2); } }
D. fn double_vec(v: &mut Vec<i32>) { for x in v { *x *= 2; } }

Solution

  1. Step 1: Understand ownership and return requirements

    The function must take ownership of the vector and return ownership back after doubling elements.
  2. 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.
  3. Final Answer:

    fn double_vec(v: Vec<i32>) -> Vec<i32> { v.iter().map(|x| x * 2).collect() } -> Option B
  4. Quick Check:

    Take ownership, return new doubled vector [OK]
Hint: Take Vec ownership and return new Vec after processing [OK]
Common Mistakes:
  • Borrowing vector but not returning ownership
  • Not returning anything from function
  • Modifying borrowed vector without ownership
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard