Bird
Raised Fist0
Rustprogramming~10 mins

Borrowing rules in Rust - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Borrowing rules
Start with variable
↓
Borrow immutably?
Yes→Allow multiple immutable borrows
↓
Use borrowed references
↓
Borrow mutably?
Yes→Allow only one mutable borrow
↓
Use mutable reference
↓
Use variable directly
↓
End or reuse variable
This flow shows how Rust checks if you borrow a variable immutably or mutably, allowing multiple immutable borrows but only one mutable borrow at a time.
Execution Sample
Rust
fn main() {
    let mut x = 5;
    let r1 = &x;       // immutable borrow
    let r2 = &x;       // another immutable borrow
    let r3 = &mut x;   // mutable borrow - ERROR
}
This code tries to borrow a variable immutably twice, then mutably once, which Rust forbids.
Execution Table
StepActionVariable StateBorrow TypeAllowed?Notes
1Declare mutable x=5x=5NoneYesVariable created mutable
2Immutable borrow r1 = &xx=5Immutable borrow #1YesFirst immutable borrow allowed
3Immutable borrow r2 = &xx=5Immutable borrow #2YesMultiple immutable borrows allowed
4Mutable borrow r3 = &mut xx=5Mutable borrowNoError: cannot borrow mutable while immutable borrows exist
5Program stopsx=5Immutable borrows activeNoBorrowing rules prevent mutable borrow here
💡 Mutable borrow denied because immutable borrows are active
Variable Tracker
VariableStartAfter Step 2After Step 3After Step 4
x5 (mutable)5 (immutably borrowed once)5 (immutably borrowed twice)5 (mutable borrow denied)
r1N/AReference to x (immutable)Reference to x (immutable)N/A
r2N/AN/AReference to x (immutable)N/A
r3N/AN/AN/AError - not created
Key Moments - 3 Insights
Why can't we create a mutable borrow when immutable borrows exist?
Rust forbids mutable borrows if any immutable borrows are active to prevent data races, as shown in step 4 of the execution_table.
Can we have multiple immutable borrows at the same time?
Yes, multiple immutable borrows are allowed simultaneously, as seen in steps 2 and 3 of the execution_table.
What happens if we try to use the mutable borrow after immutable borrows?
The compiler will give an error and prevent the mutable borrow, stopping the program as shown in step 5.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, at which step does Rust reject a borrow?
AStep 4
BStep 3
CStep 2
DStep 5
💡 Hint
Check the 'Allowed?' column for the first 'No' value in the execution_table.
According to variable_tracker, what is the state of variable 'x' after step 3?
AMutably borrowed
BImmutably borrowed twice
CNot borrowed
DMutable borrow denied
💡 Hint
Look at the 'x' row under 'After Step 3' in variable_tracker.
If we remove the immutable borrows r1 and r2, what would happen at step 4?
ACompiler error unrelated to borrowing
BMutable borrow would still be denied
CMutable borrow would be allowed
DProgram would crash
💡 Hint
Refer to the borrowing rules in concept_flow and the notes in execution_table step 4.
Concept Snapshot
Borrowing rules in Rust:
- You can have many immutable borrows at once.
- Only one mutable borrow allowed at a time.
- Mutable borrow disallowed if immutable borrows exist.
- Prevents data races and ensures safety.
- Compiler enforces these rules at compile time.
Full Transcript
This visual execution trace shows how Rust's borrowing rules work. We start with a mutable variable x. We create two immutable borrows r1 and r2, which Rust allows simultaneously. When we try to create a mutable borrow r3 while immutable borrows exist, Rust rejects it to prevent unsafe access. The variable tracker shows the state of x and references after each step. Key moments clarify why mutable borrows are denied if immutable borrows are active and confirm multiple immutable borrows are allowed. The quiz tests understanding of when borrowing is rejected, variable states, and effects of removing borrows. The snapshot summarizes the core borrowing rules that keep Rust programs safe.

Practice

(1/5)
1. What does borrowing in Rust allow you to do?
easy
A. Copy data to a new variable
B. Use data without taking ownership
C. Delete data immediately
D. Create multiple owners of data

Solution

  1. Step 1: Understand borrowing concept

    Borrowing means using data without taking ownership, so the original owner keeps control.
  2. Step 2: Compare options

    Copying or deleting data changes ownership or data state, which borrowing does not do.
  3. Final Answer:

    Use data without taking ownership -> Option B
  4. Quick Check:

    Borrowing = Use without ownership [OK]
Hint: Borrowing means using data without owning it [OK]
Common Mistakes:
  • Confusing borrowing with copying
  • Thinking borrowing deletes data
  • Assuming borrowing creates multiple owners
2. Which of the following is the correct syntax to create an immutable borrow of a variable x in Rust?
easy
A. let y = &x;
B. let y = *x;
C. let y = &mut x;
D. let y = x;

Solution

  1. Step 1: Identify immutable borrow syntax

    Immutable borrow uses &x to create a reference without allowing changes.
  2. Step 2: Check other options

    &mut x is mutable borrow, *x dereferences, and x moves ownership.
  3. Final Answer:

    let y = &x; -> Option A
  4. Quick Check:

    Immutable borrow = &x [OK]
Hint: Immutable borrow uses & before variable [OK]
Common Mistakes:
  • Using &mut for immutable borrow
  • Dereferencing instead of borrowing
  • Assigning ownership instead of reference
3. What will be the output of this Rust code?
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2);
let r3 = &mut s;
println!("{}", r3);
medium
A. hello and hello\nerror at runtime
B. hello and hello\nhello
C. Compile error due to mutable borrow while immutable borrows exist
D. hello\nhello and hello

Solution

  1. Step 1: Analyze immutable borrows

    Two immutable borrows r1 and r2 are allowed simultaneously.
  2. Step 2: Check mutable borrow after immutable borrows

    Trying to create mutable borrow r3 while immutable borrows exist causes compile error.
  3. Final Answer:

    Compile error due to mutable borrow while immutable borrows exist -> Option C
  4. Quick Check:

    Mutable borrow disallowed with active immutable borrows [OK]
Hint: No mutable borrow allowed if immutable borrows exist [OK]
Common Mistakes:
  • Assuming mutable borrow works after immutable borrows
  • Expecting runtime error instead of compile error
  • Confusing output with allowed borrows
4. Identify the error in this Rust code snippet:
let mut data = vec![1, 2, 3];
let r1 = &mut data;
let r2 = &data;
r1.push(4);
println!("{:?}", r2);
medium
A. No error, code runs fine
B. Cannot push to vector inside mutable borrow
C. Cannot print vector with {:?}
D. Cannot borrow data as immutable while mutable borrow exists

Solution

  1. Step 1: Check borrows

    Variable r1 is a mutable borrow, r2 is an immutable borrow of the same data.
  2. Step 2: Understand borrowing rules

    Rust forbids immutable borrow while mutable borrow is active, causing a compile error.
  3. Final Answer:

    Cannot borrow data as immutable while mutable borrow exists -> Option D
  4. Quick Check:

    Immutable borrow disallowed during mutable borrow [OK]
Hint: No immutable borrow allowed during mutable borrow [OK]
Common Mistakes:
  • Thinking push is invalid inside mutable borrow
  • Ignoring borrow conflict between r1 and r2
  • Assuming printing with {:?} causes error
5. You want to write a function that takes a mutable reference to a vector and appends a number, but also returns the length of the vector after appending. Which function signature and usage follow Rust's borrowing rules correctly?
hard
A. fn add_and_len(v: &mut Vec<i32>, n: i32) -> usize { v.push(n); v.len() } let mut nums = vec![1,2]; let length = add_and_len(&mut nums, 3);
B. fn add_and_len(v: &Vec<i32>, n: i32) -> usize { v.push(n); v.len() } let mut nums = vec![1,2]; let length = add_and_len(&nums, 3);
C. fn add_and_len(v: Vec<i32>, n: i32) -> usize { v.push(n); v.len() } let nums = vec![1,2]; let length = add_and_len(nums, 3);
D. fn add_and_len(v: &mut Vec<i32>, n: i32) -> usize { v.len(); v.push(n) } let mut nums = vec![1,2]; let length = add_and_len(&mut nums, 3);

Solution

  1. Step 1: Check function signature for mutable borrow

    Function needs &mut Vec<i32> to modify vector by pushing a number.
  2. Step 2: Verify function body and usage

    fn add_and_len(v: &mut Vec<i32>, n: i32) -> usize { v.push(n); v.len() } let mut nums = vec![1,2]; let length = add_and_len(&mut nums, 3); pushes number then returns length correctly; usage passes mutable reference.
  3. Step 3: Analyze other options

    fn add_and_len(v: &Vec<i32>, n: i32) -> usize { v.push(n); v.len() } let mut nums = vec![1,2]; let length = add_and_len(&nums, 3); uses immutable borrow but tries to push (not allowed). fn add_and_len(v: Vec<i32>, n: i32) -> usize { v.push(n); v.len() } let nums = vec![1,2]; let length = add_and_len(nums, 3); takes ownership, not borrow. fn add_and_len(v: &mut Vec<i32>, n: i32) -> usize { v.len(); v.push(n) } let mut nums = vec![1,2]; let length = add_and_len(&mut nums, 3); returns length before push, so length is old value.
  4. Final Answer:

    fn add_and_len(v: &mut Vec<i32>, n: i32) -> usize { v.push(n); v.len() } let mut nums = vec![1,2]; let length = add_and_len(&mut nums, 3); -> Option A
  5. Quick Check:

    Mutable borrow needed to modify vector [OK]
Hint: Use &mut to modify data inside function [OK]
Common Mistakes:
  • Using immutable borrow when modifying data
  • Taking ownership instead of borrowing
  • Returning length before modification
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