Borrowing with References

Rust’s ownership model is powerful, but sometimes you don’t want to take ownership of a value—you just want to look at it without moving it. That’s where borrowing with references comes in.

The Problem Without References #

Imagine you want to print a String from inside a function:

fn main() {
    let name = String::from("Alice");
    print_name(name); // ownership moves here
    println!("{}", name); // ❌ ERROR: name was moved
}

fn print_name(s: String) {
    println!("Name: {}", s);
}
Code language: Rust (rust)

In this code:

  • Passing name into print_name transfers ownership.
  • After that, name is no longer valid in main.

This is wasteful if we only want to read the value.

Enter References (&) #

Instead of transferring ownership, you can borrow the value with a reference:

fn main() {
    let name = String::from("Alice");
    print_name(&name); // pass a reference
    println!("{}", name); // ✅ still works, ownership not moved
}

fn print_name(s: &String) {
    println!("Name: {}", s);
}
Code language: Rust (rust)

In this example:

  • &name means “borrow name instead of moving it.”
  • The function receives a &String, not the full String.
  • Ownership stays with the caller (main), so name is still valid after the call.

References are Immutable by Default #

When you borrow with &, you cannot change the borrowed value:

fn main() {
    let name = String::from("Alice");
    print_name(&name);

    // name is still valid and unchanged
    println!("After function call: {}", name);
}

fn print_name(s: &String) {
    // s.push_str(" Smith"); ❌ ERROR: cannot modify borrowed value
    println!("Name: {}", s);
}
Code language: Rust (rust)

Rust prevents modification because multiple parts of your code might be reading it at once, and allowing mutation would be unsafe.

Why Borrowing Is Safe #

Borrowing ensures:

  • No unexpected copies → Rust avoids performance issues.
  • No data races → You can have many immutable references at once, but not a mix of mutable and immutable ones.
  • Memory safety → The owner controls when the value is dropped.

Example with Multiple References #

fn main() {
    let text = String::from("Rust");

    let r1 = &text;
    let r2 = &text;

    println!("r1: {}, r2: {}", r1, r2); // ✅ both work
    // text is still valid here too
    println!("Original: {}", text);
}
Code language: Rust (rust)

Multiple immutable references (&) are fine because they only read, never change.

Summary #

  • Ownership means one variable controls a value.
  • Borrowing (&) lets you read a value without taking ownership.
  • References are immutable by default → safe and efficient.
  • You can have many immutable references at once.
Was this Helpful ?