References & Borrowing

Rust is a systems programming language focused on speed, memory safety, and fearless concurrency — and borrowing lets you use a value without taking ownership of it, which makes ownership practical day to day.

Learn References & Borrowing in our free Rust course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Rust course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

In this lesson you'll create shared references with & , mutable references with &mut , and learn the borrow checker's rules that keep this all safe.

What You'll Learn in This Lesson

1️⃣ Shared References with &

A reference lets a function access a value without owning it. You create one with the & operator and accept one with a & type. Because the function only borrows, the original variable stays valid after the call — no move, no clone needed.

Compare this with the previous lesson: there, passing a String into a function moved it away. Here &s lends it, so s is still usable on the next line.

2️⃣ Mutable References and the Borrow Rules

To let a borrower change a value, use a mutable reference &mut . The borrow checker enforces a strict rule: at any moment you can have either any number of shared & references or exactly one &mut reference — never both. This is what prevents data races at compile time.

Notice the ordering: the two shared borrows r1 and r2 are used and finished before the mutable borrow r3 begins. Overlapping a shared and a mutable borrow would be a compile error.

Your turn. Fill in the blanks marked ___ , then run it.

Write two functions — one that borrows immutably, one that borrows mutably — and use both from main . Run it with cargo run .

📋 Quick Reference — Borrowing

Practice quiz

What does the & operator create when you write f(&s)?

  • A copy of s
  • A move of s into f
  • A reference that borrows s without taking ownership
  • A mutable clone of s

Answer: A reference that borrows s without taking ownership. & creates a reference: the function borrows the value, so the original stays valid after the call.

After let len = calculate_length(&s); is s still usable on the next line?

  • Yes, because it was only borrowed
  • No, it was moved
  • Only if s is mut
  • Only if you clone it first

Answer: Yes, because it was only borrowed. Borrowing with & does not move ownership, so s remains valid after the call.

What is the borrow rule the compiler enforces?

  • Any number of &mut at once
  • Exactly one & and one &mut together
  • References are never allowed
  • Either many shared & OR exactly one &mut, never both

Answer: Either many shared & OR exactly one &mut, never both. At any time you may have many shared references or one mutable reference, but not both simultaneously.

Why must the owner be declared with mut to create a &mut reference to it?

  • For naming reasons only
  • Because a mutable reference can change the value, so the owner must permit mutation
  • Because &mut copies the value
  • It does not need to be mut

Answer: Because a mutable reference can change the value, so the owner must permit mutation. You can only hand out a &mut to a value whose owner allows mutation, declared with let mut.

What does this print? let s = String::from("hello"); println!("{}", calculate_length(&s)); // fn calculate_length(text: &String) -> usize { text.len() }

  • 5
  • hello
  • &hello
  • It does not compile

Answer: 5. text.len() returns the byte length of "hello", which is 5.

What does add_excitement print? let mut m = String::from("hello"); add_excitement(&mut m); println!("{}", m); // fn add_excitement(text: &mut String) { text.push_str("!!!"); }

  • hello
  • !!!
  • hello!!!
  • It does not compile

Answer: hello!!!. The &mut reference lets the function append "!!!" in place, so m becomes hello!!!.

Which is valid at the same time?

  • Two &mut to the same value
  • Several shared & references at once
  • One &mut and one & overlapping
  • A reference to dropped data

Answer: Several shared & references at once. Multiple shared references are fine together; only a single &mut is exclusive.

How do you call a function declared as fn f(x: &String)?

  • f(s)
  • f(*s)
  • f(mut s)
  • f(&s)

Answer: f(&s). Pass a reference with &s; calling f(s) would move the String instead of borrowing it.

Which is more general and usually preferred in function signatures?

  • &String
  • &str
  • String
  • Box<String>

Answer: &str. &str is more general; a String coerces to &str, so idiomatic functions take &str.

What guarantee do Rust references always provide?

  • They are nullable
  • They may dangle
  • They always point to valid data (no dangling pointers)
  • They are always mutable

Answer: They always point to valid data (no dangling pointers). The borrow checker ensures references never outlive the data they point to.