Skip to content

Instantly share code, notes, and snippets.

@simonholm
Created July 13, 2025 07:34
Show Gist options
  • Save simonholm/7661d600d0d5f1a48ec5ee1faf287d4f to your computer and use it in GitHub Desktop.
Save simonholm/7661d600d0d5f1a48ec5ee1faf287d4f to your computer and use it in GitHub Desktop.

Fixing a Borrow Checker Violation in Rust

This post explains a common borrow checker error in Rust and shows how to fix it using idiomatic code.


❌ Problematic Code

The original Rust code shared in a code challenge was:

fn main() {
    let mut vec: Vec<i32> = vec![1, 2, 3, 4, 5];
    let mut sum: i32 = 0;

    for i in 0..vec.len() {
        let x = &vec[i].clone();
        vec.push(6);
        sum += *x;
    }

    let result: String = format!("Sum is: {}", sum.to_string());
    println!("{}", result);
}

This won't compile due to a borrow checker error:

  • vec[i] temporarily borrows vec immutably.
  • vec.push(6) tries to mutably borrow it at the same time.
  • Rust prevents this to avoid data races and undefined behavior.

🧠 Why This Is Tricky

Aspect Explanation
clone() Appears safe, but the way it's written causes a temporary borrow of vec
Borrow lifetime The borrow from vec[i] lives too long β€” across the push call
Mutation conflict vec.push(6) needs mutable access, which conflicts with the immutable borrow

This pattern is misleading because clone() seems to produce an independent value, but the access to vec[i] still creates a short-lived borrow that overlaps with the mutation.


βœ… Idiomatic Fix

We restructure the code to make the clone explicit before any mutation:

fn main() {
    let mut vec: Vec<i32> = vec![1, 2, 3, 4, 5];
    let mut sum: i32 = 0;

    for i in 0..vec.len() {
        let cloned = vec[i].clone(); // take the value early
        vec.push(6);                 // mutate later β€” now it's safe
        sum += cloned;
    }

    let result: String = format!("Sum is: {}", sum);
    println!("{}", result);
}

βœ… Key Benefits

  • No references held across a mutation
  • clone() result is owned β€” no borrow involved
  • Intent is clearer, and Rust can verify memory safety

🧾 Takeaways

  • Clone early to avoid borrowing overlaps
  • Understand that even "temporary" borrows from indexing (vec[i]) can interfere
  • Rust’s borrow checker errs on the side of safety β€” especially across loop iterations and mutation
  • Breaking operations into clear, separate steps helps the compiler and the reader

πŸ“š Tags

#RustLang #BorrowChecker #CodeChallenge #IdiomaticRust

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment