RustArena

Step 6 of 7

When to return owned data instead

Some lifetime errors have no lifetime fix at all. The most common one:

fn make_greeting(name: &str) -> &str {
    let greeting = format!("Hello, {name}!");
    &greeting
}

fn main() {
    println!("{}", make_greeting("Ferris"));
}
error[E0515]: cannot return reference to local variable `greeting`
 --> src/main.rs:3:5
  |
3 |     &greeting
  |     ^^^^^^^^^ returns a reference to data owned by the current function

The signature is fine as far as elision goes (one input, so rule 2 says the result borrows from name). The body breaks that promise: greeting is a new String owned by make_greeting, and it's dropped when the function returns. Any reference to it would dangle. Writing <'a> everywhere changes nothing, and neither does 'static: the data simply doesn't exist after the function ends. (Returning greeting.as_str() gives the same error in another wording: "returns a value referencing data owned by the current function".)

The fix is to return the owned value: give ownership of the String to the caller.

fn make_greeting(name: &str) -> String {
    format!("Hello, {name}!")
}

fn first_name(full: &str) -> &str {
    full.split(' ').next().unwrap_or(full)
}

fn main() {
    let full = String::from("Ana Lovelace");
    println!("{}", make_greeting(first_name(&full)));
}
Hello, Ana!

Moving a String out of a function is cheap: only the pointer, length and capacity are copied, never the text.

Borrow or own? A rule of thumb

Experienced Rust developers return owned data far more often than beginners expect. It's not giving up; it's choosing the simplest correct design.

Common mistakes

Your task

Fix the three functions. make_greeting and initials build new strings, so they must return owned data. last_name only selects part of its input: keep it returning a &str. Results: make_greeting("Ana") is Hello, Ana!, initials("Ada Lovelace") is A.L., last_name("Ada Lovelace") is Lovelace.

Challenge 2

Report borrows its title, but build_report creates the title with format!, so there's nothing long-lived to borrow from. Change Report to own its title (and drop the lifetime parameter), so build_report("sales", &[3, 4]) returns a report with title Report: sales and total 7.

Challenge 3

Write two functions over a list of words:

Notice the signature of longest_word: the result is tied to the words (&'a str), not to the slice holding them. A hidden test throws the slice away and keeps the word.

Previous: 'static: references that live forever Next: Reading lifetime errors