100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Rust

Borrowing and References in Rust

How Rust lets code access data without taking ownership, using immutable and mutable references checked by the borrow checker.

Ownership & BorrowingBeginner10 min readJul 8, 2026
Analogies

Introduction

Moving ownership every time you want to pass data to a function would be tedious - you'd have to keep returning it back. Rust solves this with borrowing: you can create a reference to a value without taking ownership of it. References let functions and code blocks read or modify data temporarily, and the borrow checker enforces rules at compile time that prevent data races and dangling references.

🏏

Cricket analogy: Instead of handing the bat outright to a net bowler and waiting for it back, a captain lets a teammate borrow it for a few throws while he keeps official possession, and the coach enforces rules so no two players swing at once.

Syntax

rust
let s = String::from("hello");
let r1: &String = &s;      // immutable reference
let len = calculate_length(r1);

let mut m = String::from("hi");
let r2: &mut String = &mut m; // mutable reference
r2.push_str(" there");

Explanation

A reference, written with &, lets you 'borrow' a value without owning it - the underlying value is not moved or dropped when the reference goes out of scope. The borrow checker enforces a strict rule: at any given time, you may have either exactly one mutable reference (&mut T) or any number of immutable references (&T) to a piece of data, but never both at once. This prevents data races at compile time, because two simultaneous writers, or a writer and a reader, can never observe inconsistent state. References must also always be valid - Rust rejects any reference that could outlive the data it points to, which eliminates dangling references entirely.

🏏

Cricket analogy: A team can field any number of fans watching from the stands (immutable readers), but only one player at a time is allowed to actually bat and change the scoreboard (mutable writer), never both kinds at once.

Example

rust
fn calculate_length(s: &String) -> usize {
    s.len() // borrows s, doesn't take ownership
}

fn append_world(s: &mut String) {
    s.push_str(" world");
}

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);
    println!("'{}' has length {}", s1, len); // s1 still valid

    let mut s2 = String::from("hello");
    append_world(&mut s2);
    println!("{}", s2);

    // let r1 = &mut s2;
    // let r2 = &mut s2; // compile error: second mutable borrow
}

Output

text
'hello' has length 5
hello world

Key Takeaways

  • &T creates an immutable reference; &mut T creates a mutable reference.
  • You can have many immutable references, or exactly one mutable reference, but never both at the same time.
  • References must always point to valid data - dangling references are rejected at compile time.
  • Borrowing lets functions use data without taking ownership, so the caller keeps using the value afterward.
  • These rules eliminate data races and use-after-free bugs without any runtime checks.

Practice what you learned

Was this page helpful?

Topics covered

#Rust#RustProgrammingStudyNotes#Programming#BorrowingAndReferencesInRust#Borrowing#References#Syntax#Explanation#StudyNotes#SkillVeris