C.W.K.
Stream
Lesson 03 of 05 · published

Lifetimes in Function Signatures

~12 min · lifetimes, functions, longest

Level 0Rust Curious
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

The single most common place you'll write a lifetime is a function that takes references and returns one. This is the canonical example — the one the Rust Book uses — because it captures the whole idea.

The longest function

Write a function that returns the longer of two string references. The compiler hits a wall: the returned reference borrows from one of the inputs, but which one depends on a runtime comparison. Without help, it can't prove the output won't outlive whichever input it came from. So it asks you to annotate.

Same lifetime, shared fate

Annotating both parameters and the return with the same 'a tells the compiler: 'the result is valid for the overlap of both inputs' lifetimes.' Now it can prove safety: as long as both inputs are alive, the returned reference is valid; once either dies, you can't use the result. The annotation didn't change behavior — it supplied the missing fact.

You annotate to resolve ambiguity, not to control lifetimes. The compiler already knows how long everything lives. The 'a tells it how the output's validity relates to the inputs' — a relationship it couldn't infer when the answer depends on runtime logic.

When inputs have different lifetimes

If the output only ever borrows from one specific parameter, only that one needs the shared lifetime; the other can be independent. Getting precise about which input the output borrows from is the real skill — and the compiler errors guide you straight to it.

Code

The canonical longest function·rust
// Both inputs and the output share lifetime 'a:
// the result is valid as long as BOTH x and y are.
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

fn main() {
    let a = String::from("a long string");
    let result;
    {
        let b = String::from("short");
        result = longest(&a, &b);
        println!("{result}"); // fine: used while both are alive
    }
    // println!("{result}"); // error: b is gone, result may dangle
}

External links

Exercise

Write longest with the shared 'a. Then construct a case where it correctly fails to compile: return the result from a scope where one of the inputs has already been dropped. Read the error and confirm the borrow checker caught a real dangle.
Hint
Put one input in an inner scope, call longest, and try to use the result after that scope ends. The shared 'a ties the result to both inputs, so using it past the shorter-lived input's death is rejected.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue
💛 by Ttoriwarm

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.