Question
In Rust, I have seen types and annotations written with a leading apostrophe, such as:
'static
'r
'a
What does the apostrophe (') mean in these cases?
Are these related to references like &T? Are they a kind of generic parameter that applies specifically to references?
I am trying to understand what these identifiers represent and where they fit into Rust's type system.
Short Answer
By the end of this page, you will understand that names like 'a, 'r, and 'static in Rust are lifetimes. Lifetimes describe how long references are valid, helping Rust prevent dangling references at compile time. You will see how lifetime annotations appear in function signatures, structs, and reference types, and how 'static is a special lifetime with a distinct meaning.
Concept
In Rust, an identifier that starts with an apostrophe, such as 'a, usually represents a lifetime.
A lifetime is Rust's way of describing how long a reference is allowed to stay valid. Since Rust cares deeply about memory safety, it must ensure that references never outlive the data they point to.
For example, if a reference points to a local variable inside a function, that reference cannot be used after the variable goes out of scope. Rust checks this at compile time.
Why lifetimes exist
Rust allows you to use references instead of copying data everywhere. That is efficient, but it creates a risk:
- a reference might point to data that has already been dropped
- this would create a dangling reference
Rust prevents that by tracking lifetimes.
What the apostrophe means
The apostrophe is simply part of the syntax for naming a lifetime:
'a'r'input'static
These are not string literals, not characters, and not special modifiers on & by themselves. They are names used by the compiler to reason about borrowing.
Lifetimes and references
Lifetimes are most commonly seen with references because references are the values that depend on something else remaining alive.
For example:
Mental Model
Think of a reference as a library card that lets you access a book without owning it.
The lifetime is the expiration date on that card.
&Tmeans you have access to the book'ameans how long that access card stays valid- Rust checks that your card does not expire before you try to use it
So if a function returns a reference, Rust wants to know: which original value does that reference depend on, and how long is it safe to use?
'static is like a card that never expires during the whole program run.
This model helps explain why lifetimes are attached to borrowed data rather than owned values. Owned values manage their own memory. References borrow someone else's memory, so Rust must track validity.
Syntax and Examples
Core syntax
Lifetime parameter declaration
fn example<'a>(value: &'a str) -> &'a str {
value
}
Reference with an explicit lifetime
let s: &'static str = "hello";
Struct holding a reference
struct UserName<'a> {
name: &'a str,
}
A struct that stores a reference usually needs a lifetime parameter, because the struct cannot outlive the data it borrows.
Beginner-friendly example
fn first_word<'a>(text: &'a str) -> &'a str {
match text.split_whitespace().() {
(word) => word,
=> ,
}
}
() {
= ::();
= (&sentence);
(, word);
}
Step by Step Execution
Consider this function:
fn longer<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
fn main() {
let s1 = String::from("cat");
let s2 = String::from("elephant");
let result = longer(&s1, &s2);
println!("{}", result);
}
Step by step
s1is created and owns the string"cat".s2is created and owns the string"elephant".&s1creates a reference to the contents of .
Real World Use Cases
Lifetimes show up whenever code borrows data instead of owning it.
Common real uses
- String processing: returning slices like
&strinstead of allocating newStringvalues - Parsers: storing references into the original input buffer
- Configuration views: borrowing parts of larger config data
- Structs with borrowed fields: avoiding unnecessary cloning
- APIs that avoid allocation: returning borrowed data for performance
Example: parsing without copying
struct Header<'a> {
key: &'a str,
value: &'a str,
}
This lets a parser read text and store references to pieces of the original input, instead of creating new owned strings for every field.
Example: efficient helper functions
fn trim_and_keep<'a>(s: &'a str) -> &'a str {
s.trim()
}
This returns a borrowed slice of the original string instead of allocating a new one.
Real Codebase Usage
In real Rust projects, developers often use lifetimes indirectly through references, slices, and iterators. Explicit lifetime annotations usually appear when the relationship between borrows must be spelled out.
Common patterns
Guarding borrowed inputs
fn non_empty<'a>(s: &'a str) -> Option<&'a str> {
if s.is_empty() {
None
} else {
Some(s)
}
}
This pattern keeps the returned borrow tied to the input.
Borrowed views instead of owned copies
struct RequestView<'a> {
path: &'a str,
method: &'a str,
}
This is common in parsers, web frameworks, and protocol handling code.
Returning slices from collections
fn first_item<'a>(items: &'a [i32]) <& > {
items.()
}
Common Mistakes
1. Thinking 'a creates data
It does not create or store data. It only describes how long a reference is valid.
Broken mental model:
// 'a is not a value and does not allocate anything
2. Confusing 'static with "always better"
'static is not a general replacement for other lifetimes.
Broken example:
fn wrong() -> &'static str {
let s = String::from("hello");
&s
}
This fails because a local variable does not live for the whole program.
3. Returning a reference to local data
fn broken<'a>() -> &'a str {
let text = String::from();
&text
}
Comparisons
Lifetimes vs related Rust concepts
| Concept | What it describes | Example | Owns data? |
|---|---|---|---|
| Lifetime parameter | How long a borrow is valid | 'a | No |
| Reference | Borrowed access to data | &str | No |
| Mutable reference | Exclusive borrowed access | &mut String | No |
| Generic type parameter | A placeholder for a type | T | Not by itself |
| Owned value | Data that manages its own memory | String |
Cheat Sheet
Quick reference
Lifetime syntax
'a
'input
'ctx
'static
Reference with lifetime
&'a T
&'a str
&'a mut T
Function with a lifetime parameter
fn example<'a>(x: &'a str) -> &'a str {
x
}
Struct with borrowed data
struct Item<'a> {
name: &'a str,
}
Meaning of 'static
let msg: &'static str = "hello";
FAQ
What does the apostrophe mean in Rust types?
It usually introduces a lifetime, such as 'a or 'static. Lifetimes describe how long a reference is valid.
Is 'a part of a reference type?
It is not the reference itself, but it is often attached to references, like &'a str, to describe the borrow's lifetime.
Are lifetimes like generics in Rust?
Yes. A lifetime parameter like 'a is similar to a type parameter like T, but it represents duration of validity rather than a type.
What is the difference between 'a and 'static?
'a is a named lifetime parameter chosen for a specific context. 'static is a special lifetime meaning the data can live for the entire program.
Why do some functions not show lifetimes at all?
Rust can infer many lifetimes automatically using lifetime elision rules.
Do lifetimes affect runtime performance?
Usually no. Lifetimes are mainly checked at compile time.
Why do structs with references need lifetimes?
Because Rust must know how long the referenced data must stay alive for the struct to remain valid.
Mini Project
Description
Build a small Rust program that returns borrowed pieces of text without allocating new strings. This demonstrates why lifetimes exist and how they let functions safely return references tied to input data.
Goal
Create a function that finds the longer of two string slices and returns a safe borrowed reference to it.
Requirements
- Write a function that accepts two
&strvalues. - Return the longer string slice without creating a new
String. - Use an explicit lifetime annotation in the function signature.
- Test the function with two different input strings.
Keep learning
Related questions
Accessing Cargo Package Metadata in Rust
Learn how to read Cargo package metadata like version, name, and authors in Rust using compile-time environment macros.
Associated Types vs Generic Type Parameters in Rust: When to Use Each
Learn when to use associated types vs generic parameters in Rust traits, with clear rules, examples, and practical API design advice.
Convert an Integer to a String in Rust
Learn the current Rust way to convert integers to strings, why `to_str()` no longer works, and when to use `to_string()` or `format!`.