[Avg. reading time: 14 minutes]

Borrowing References

Borrowing allows you to use a value without taking ownership.

Rust enforces strict rules to prevent:

  • Data races
  • Dangling references
  • Undefined behavior

These rules are checked at compile time by the borrow checker.


Borrowing Immutable References

An immutable reference allows read-only access.

// Cannot modify through immutable reference

fn changeme(param_msg: &String) {
    // param_msg.push_str(" Green"); // ❌ not allowed
    println!("{param_msg}");
}

fn main() {
    let msg = String::from("Rachel");
    changeme(&msg);
}

Why this fails if uncommented:

  • &String is immutable

Example: Borrow a book from the library; you cannot write anything. Just read from it.

Borrowing Mutable References

A mutable reference allows read and write access.

// Mutable reference

fn changeme(param_msg: &mut String) {
    param_msg.push_str(" Green")
}

fn main() {
    let mut msg = String::from("Rachel");
    changeme(&mut msg);
    println!("{}", msg);
}

Requirements:

  • The original variable must be mut
  • The reference must be &mut

Example: Borrow a book from a friend with permission to highlight or underline important items.

Immutable Borrow

  • Allows read-only access to a value.
  • Multiple immutable borrows are allowed.
  • No mutation allowed through immutable reference.
// Immutable Borrow

fn main() {
    let x = 5;
    
    // Immutable borrow
    let y = &x;
    *y += 1;
    println!("Value of y: {}", y);
}

Mutable Borrow

Grants read-write access to a value. Only one mutable borrow is allowed at a time, and no immutable borrows can coexist.

// Mutable Borrow - Stack

fn main() {
    let mut x = 5;
    println!("Value of x: {}", x);
    
    // Mutable borrow
    let z = &mut x;
    *z += 1;
    println!("Value of x: {}", x);
}

Rule:

  • You cannot have an active mutable borrow and immutable borrow at the same time.
  • After the mutable borrow goes out of scope, immutable borrows are allowed.

That’s why they always use immutable borrows after mutable borrows.

fn main() {
    let mut x = 5;
    
    // Mutable borrow
    let z = &mut x;
    *z += 1;
    
    println!("Value of z: {}->{:p}", z, &z);
    
    println!("Value of x: {}->{:p}", x, &x);
    
    // immutable borrows
    let y1 = &x;
    println!("Value of y1: {}->{:p}", y1, &y1);
    
    // Flip the immutable and mutable and print the Immutable value after Mutable
}

Use this website to sort the Memory locations to understand how values are stored in Stack. You can sort them by ASC or DESC order.

https://www.rajeshvu.com/storage/emc/utils/general/sorthexnumbers

Borrow Checker

// Borrow Checker - String - Heap

fn main() {
    let mut a = String::from("Rachel");
    
    let b = &mut a;
    
    println!("variable 'b' initial value is {} stored at this {:p}", b,b.as_ptr());
    
    b.push_str(" Green");
    
    //println!("variable 'a' {}{:p}", a,a.as_ptr());
    
    println!("variable 'b' {} {:p}", b,b.as_ptr());
    
    // println!("variable 'a' {}{:p}", a,a.as_ptr());
    
    b.push_str(" !");
    
    println!("variable 'b' after update {},{:p}", b,b.as_ptr());
    
    println!("variable 'a' after update {} {:p}", a,a.as_ptr());
}

Why a cannot be used while b exists:

  • b has exclusive access

Rust prevents simultaneous access to avoid data races

Example: The book owner can use the book only after the borrowed person has completed the work.

Multiple Mutable Borrowers (not allowed)

// Not allowed to have multiple Mutable Borrowers at the same time/scope

fn main() {
    let mut a = String::from("Rachel");
    
    let b = &mut a;
    let c = &mut a;
    
    println!("{}", b);
    println!("{}", c);
   
}

Example: Two friends borrow the same book to highlight the important items.

// Multiple Mutable Borrowers (different scope)

fn main() {
    let mut a = String::from("Rachel");
   
    let b = &mut a;
    println!("{}", b);

    let c = &mut a;
    println!("{}", c);
}
  • Only one mutable reference exists at a time
  • Scopes do not overlap

Example: 2 friends borrow the book one after another for writing.

For clarity’s sake, the above code can be written this way, too.

// Multiple Mutable Borrowers (different scope)

fn main() {
    let mut a = String::from("Rachel");

    {    
       let b = &mut a;
        println!("{}", b);
    }

    let c = &mut a;
    println!("{}", c);
}

Immutable and Mutable

Mutable first, followed by Immutable

// Immutable and Mutable

fn main() {
    let mut a = String::from("Rachel");
    
    let c = &mut a;
    c.push_str("!");
    println!("c = {}", c);
    
    let b = &a;
    println!("b = {}", b);

Borrowing is what allows Rust to provide:

  • Memory safety
  • Data race prevention
  • No garbage collector
  • Zero runtime overhead

Rules:

  • Multiple immutable references are allowed.
  • Only one mutable reference is allowed at a time.
  • Mutable and immutable references cannot coexist simultaneously.
  • References must always be valid (no dangling references).

#borrowing #referencesVer 2.0.12

Last change: 2026-02-18