Course contentsShow
← Rust
Lesson 205 of 1,9103. Borrowing and ReferencesFree lesson

Comparing References vs Values

Decide when to accept a value or a reference in a function based on ownership needs.

In this lesson, you will learn how to choose between taking ownership of a value versus borrowing it as a reference when designing your functions.

The Decision: Ownership or Borrowing?

When you pass data to a function, you are choosing between two fundamental paths:

  1. Taking Ownership (T): The function becomes the new owner of the data. Once the function finishes, the data is dropped (cleaned up).
  2. Borrowing (&T): The function gets temporary access to the data. The original owner keeps control, and the data remains alive after the function finishes.

When to Take a Value

Take a value (ownership) when the function needs to consume or transform the data, or when the function's entire purpose is to destroy or store it. For example, if you are writing a function that adds an item to a list, the list needs to "own" that data to keep it stored in memory.

When to Take a Reference

Take a reference when the function only needs to read the data to perform a calculation or a check. Using a reference is more efficient because it avoids moving or copying large amounts of data. It also allows the caller to continue using their variable after the function returns.

Consider this example:

fn print_length(s: &String) { // Borrowing: we just need to look at it
    println!("The length is {}", s.len());
}

fn consume_string(s: String) { // Taking ownership: we are finished with it
    println!("Taking full control: {}", s);
} // s is dropped here!

fn main() {
    let my_str = String::from("Hello");
    
    print_length(&my_str); // We borrow it
    consume_string(my_str); // We give it away
    
    // print_length(&my_str); // ERROR: my_str no longer exists here!
}

By default, lean toward using references (&T). Only pass by value (T) if the function explicitly needs to "own" the resource to move it into another structure or free it. This keeps your program's memory usage predictable and your functions flexible for the caller.

Key Takeaway: Choose references to grant temporary access for reading, and choose values only when your function needs to take permanent ownership or "consume" the data.