Thuta Learning
Rust
BasicProgrammingbeginner

References and Borrowing

What you'll walk away with

  • Explain the core ideas behind References and Borrowing
  • Run the sample Rust code and verify its output
  • Apply the technique correctly to the Tutorial Platform and production scenarios

Build the mental model

To avoid moving ownership as in Lesson 6, you can "borrow" a value with a reference (`&`) — passing `&content` to a function leaves ownership with the caller, and the function only gets temporary permission to look at the value; the borrow ends when the function returns. References are immutable (`&T`) by default; to change the value, you must explicitly request a mutable reference (`&mut T`). The borrow checker's core rule is that, in the same scope, a value can have either exactly one mutable reference or any number of immutable references — never both at once — which prevents read-write conflicts (one place reading data while another mutates it) from ever occurring, at compile time. Think of it like a library book: no one else can read it while someone is editing it in pencil (data could get corrupted), but as long as no one is editing, many people can safely read it at once. Enforcing this rule at compile time is what extends it across threads in the concurrency lesson (Lesson 18) too, turning a data race into a compiler error rather than a runtime bug.

Connect it to a real scenario

Write the content analyzer's `count_words` as `fn count_words(text: &str) -> u32`, borrowing rather than owning, so the caller's original `String` remains usable after calling it. To update the lesson stats vector in place, pass a mutable reference: `fn update_stats(stats: &mut Vec<LessonStat>) { ... }` — while it's active, no other reference (mutable or immutable) to that vector can be alive at the same time, and the compiler enforces this automatically. For report-generation functions that only need to read the files array, consistently use `&Vec<LessonStat>` (an immutable borrow) so multiple functions can read it concurrently.

Try the working example

rust
fn count_words(text: &str) -> u32 {
    text.split_whitespace().count() as u32
}

fn append_tag(tags: &mut Vec<String>, tag: &str) {
    tags.push(tag.to_string());
}

fn main() {
    let content = String::from("Rust references and borrowing");
    let count = count_words(&content);
    println!("{content} -> {count} words"); // content still usable

    let mut tags = vec![String::from("rust")];
    append_tag(&mut tags, "ownership");
    println!("{tags:?}");
}
You should see
You print "Rust references and borrowing -> 4 words" and `["rust", "ownership"]`.

5-minute try-it

Create a `Vec<String>` variable and take two immutable references (`&v`) to it at the same time (allowed) — then, while one immutable reference is still active, try taking a mutable reference (`&mut v`) too — read the resulting compile error.

One important caution

Trying to take a mutable and an immutable reference to the same value in the same scope at once — the borrow checker immediately blocks it with "cannot borrow as mutable because it is also borrowed as immutable."

Writing a function's parameter as owned (`String`) when a borrow (`&str`) would suffice, forcing every caller into an unnecessary ownership move — designing borrow-first gives callers more flexibility.

The Rust Programming Language — References and BorrowingRust

Easy traps

  • Trying to take a mutable and an immutable reference to the same value in the same scope at once — the borrow checker immediately blocks it with "cannot borrow as mutable because it is also borrowed as immutable."
  • Writing a function's parameter as owned (`String`) when a borrow (`&str`) would suffice, forcing every caller into an unnecessary ownership move — designing borrow-first gives callers more flexibility.
  • Validate sample code in a local or test environment before applying it to a production system.

Exercise

Create a `Vec<String>` variable and take two immutable references (`&v`) to it at the same time (allowed) — then, while one immutable reference is still active, try taking a mutable reference (`&mut v`) too — read the resulting compile error.

You'll know it worked when: You print "Rust references and borrowing -> 4 words" and `["rust", "ownership"]`.

References and Borrowing | Thuta Learning