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.
'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.