Course contentsShow
← Rust
Lesson 93 of 1,9102. The Ownership ModelFree lesson

Return Values and Ownership Transfers

Implement functions that efficiently return control of large structures back to the caller.

Returning Ownership to the Caller

In this lesson, you will learn how to efficiently pass ownership of data from a function back to the code that called it.

When you create a large data structure inside a function, Rust’s ownership rules dictate that the data is dropped when the function scope ends. If you want to keep that data alive after the function finishes, you must transfer ownership back to the caller.

Moving Data Out

In Rust, returning a value is synonymous with a "move." When you return a variable from a function, the ownership is transferred from the function's scope to the scope of the caller. This process is highly efficient because Rust does not copy the actual data on the heap; instead, it moves the pointer, length, and capacity metadata from the stack of the function to the stack of the caller.

Consider this example where we create a large Vec inside a function:

fn create_large_dataset() -> Vec<i32> {
    let data = vec![1, 2, 3, 4, 5]; // Data created on the heap
    data // Ownership is moved out to the caller
}

fn main() {
    let my_data = create_large_dataset(); // Ownership is transferred here
    println!("{:?}", my_data);
}

Why this is efficient

Because the Vec manages its own memory on the heap, the function doesn't need to "manually" return a pointer or deal with complex cleanup logic. By simply stating the variable name as the return expression, you are telling the compiler: "I am finished with this; the caller now owns this memory."

The caller receives the exact same pointer that the function was using, with no performance penalty for the actual heap data. The function's stack frame is popped, but the data survives because the caller has assumed responsibility for it. This pattern allows you to write modular code that generates complex resources without worrying about manual memory management or unnecessary data duplication.

Key Takeaway: Returning a value from a function is a move operation that transfers ownership, allowing the caller to take control of heap-allocated memory without any data copying.