Question
Why Rust Cannot Store a Value and a Reference to It in the Same Struct
Question
I want to create a Rust type that stores both an owned value and a reference to that value, or to data derived from it.
For example:
#[derive(Copy, Clone)]
struct Thing {
count: u32,
}
struct Combined<'a>(Thing, &'a u32);
fn make_combined<'a>() -> Combined<'a> {
let thing = Thing { count: 42 };
Combined(thing, &thing.count)
}
I also run into the same issue when trying to store a value and a reference to the whole value in the same struct:
#[derive(Copy, Clone)]
struct Thing {
count: u32,
}
struct Combined<'a>(Thing, &'a Thing);
fn make_combined<'a>() -> Combined<'a> {
let thing = Thing { count: 42 };
Combined(thing, &thing)
}
And sometimes I get a similar lifetime error even when the second field is not obviously a direct reference, but is a value that internally borrows from the first one:
struct Parent;
struct Child<'a>(&'a Parent);
impl Parent {
fn new() -> Self {
Parent
}
fn child(&self) -> Child<'_> {
Child(self)
}
}
struct Combined<'a>(Parent, Child<'a>);
fn make_combined<'a>() -> Combined<'a> {
let parent = Parent::new();
let child = parent.child();
Combined(parent, child)
}
In all of these cases, Rust reports that one of the values "does not live long enough." What exactly does that mean, and why does Rust reject this pattern?
Short Answer
By the end of this page, you will understand why Rust usually does not allow a struct to own a value and also store a reference into that same value. You will learn what lifetime errors like "does not live long enough" mean, why moving a value makes internal references unsafe, and which Rust-friendly alternatives are commonly used instead.
Concept
In Rust, a reference must always point to valid data for as long as the reference is used. This rule is enforced at compile time through borrowing and lifetimes.
The core problem in your examples is that the struct you are trying to build would be self-referential: one field owns the data, and another field points into that owned data.
That sounds reasonable at first, but Rust rejects it in ordinary safe code because owned values can be moved. When a value is moved, its memory location may change. If another field inside the same struct stores a reference to the old location, that reference could become invalid.
Consider this idea:
struct Combined<'a>(Thing, &'a u32);
If the second field references the first field's contents, then Combined contains a pointer into itself. But Rust does not guarantee that the struct will stay at one fixed memory address after it is created. Moving the struct could invalidate that internal reference.
This is why the compiler stops you earlier: it sees that the reference you are trying to store is tied to a local variable like thing, and that local variable will go out of scope when the function returns.
What "does not live long enough" means
A value's lifetime is the span of code during which it is valid.
In this function:
fn make_combined<'a>() Combined<> {
= Thing { count: };
(thing, &thing.count)
}
Mental Model
Think of a struct as a box you can pick up and move.
- The owned value is like a book placed inside the box.
- A reference is like a sticky note that says, "look at page 10 of the book in this exact position."
If you move the whole box to another place and the sticky note depends on the book staying at the same exact spot, the note may no longer point correctly.
Rust avoids this by saying: if something inside the box points to another thing inside the same box, that is dangerous unless the box is guaranteed not to move.
Another way to think about it:
- Owned data = you own the house.
- Reference = you wrote down the house address.
- If the house itself can be relocated, the old address becomes wrong.
Rust wants references to behave like reliable addresses, so it prevents patterns where moving values could silently break them.
Syntax and Examples
The pattern that fails
Here is the common pattern that beginners try first:
#[derive(Copy, Clone)]
struct Thing {
count: u32,
}
struct Combined<'a> {
thing: Thing,
count_ref: &'a u32,
}
fn make_combined<'a>() -> Combined<'a> {
let thing = Thing { count: 42 };
Combined {
thing,
count_ref: &thing.count,
}
}
This fails because count_ref borrows from thing, and thing is a local variable whose lifetime ends when the function returns.
A Rust-friendly alternative: store owned data only
Instead of storing both the value and a reference into it, store just the owned value and access the inner field when needed:
#[derive(Copy, Clone)]
struct Thing {
count: u32,
}
struct Combined {
thing: Thing,
}
impl {
(&) & {
&.thing.count
}
}
() Combined {
Combined {
thing: Thing { count: },
}
}
Step by Step Execution
Consider this example:
#[derive(Copy, Clone)]
struct Thing {
count: u32,
}
struct Combined<'a>(Thing, &'a u32);
fn make_combined<'a>() -> Combined<'a> {
let thing = Thing { count: 42 };
let count_ref = &thing.count;
Combined(thing, count_ref)
}
Step-by-step
1. thing is created
let thing = Thing { count: 42 };
thingis a local variable.- It lives only until the end of
make_combined.
2. A reference is taken
let count_ref = &thing.count;
Real World Use Cases
This concept matters whenever data relationships look like "one object owns data, another part points inside it."
Common situations
- Parsing text: a parser owns a
String, and tokens want to borrow slices from it. - Tree structures: a node owns children, and each child wants a direct reference back to the parent.
- Configuration objects: one field stores full config data, another field wants to cache a borrowed part.
- Database results: a row owns raw bytes, and decoded fields want to borrow from those bytes.
- API responses: one struct owns response data, and another field tries to keep references into it.
Practical Rust approach
In real apps, developers usually avoid self-references by using one of these patterns:
- compute borrowed views on demand
- store IDs, keys, or indexes instead of references
- split ownership across separate values
- use
Rc,Arc, orBoxfor indirection when appropriate - allocate long-lived backing storage in an arena
These designs are easier to reason about and work well with Rust's ownership model.
Real Codebase Usage
In real Rust codebases, developers rarely store internal references in ordinary structs. Instead, they redesign the data model.
Common patterns
Guarded access through methods
Store only the owner, then borrow from it when needed:
struct Document {
text: String,
}
impl Document {
fn first_char(&self) -> Option<&str> {
self.text.get(0..1)
}
}
Store offsets instead of references
This is common in parsers and text processing:
struct Token {
start: usize,
end: usize,
}
struct ParsedFile {
source: String,
tokens: Vec<Token>,
}
impl ParsedFile {
fn token_text(&self, token: &Token) -> &str {
&self.source[token.start..token.end]
}
}
Common Mistakes
1. Assuming moving into a struct keeps references valid
Broken code:
struct Combined<'a> {
thing: Thing,
count_ref: &'a u32,
}
fn make_combined<'a>() -> Combined<'a> {
let thing = Thing { count: 42 };
Combined {
thing,
count_ref: &thing.count,
}
}
Why it fails:
count_refborrows from the local variablething- that local variable does not live long enough for the returned value
How to fix it:
- store only
thing - create the reference later with a method
2. Thinking lifetimes extend object ownership
A lifetime parameter like 'a does not make data live longer.
Broken idea:
fn make_combined<'a>() -> Combined<> {
= Thing { count: };
(thing, &thing.count)
}
Comparisons
Self-reference vs Rust-friendly alternatives
| Approach | Stores internal reference? | Safe in ordinary structs? | Common use case |
|---|---|---|---|
| Own value + reference into same value | Yes | No | Usually rejected by borrow checker |
| Own value + method returns borrow | No | Yes | Most common replacement |
| Own value + copied field | No | Yes | Small Copy data like numbers |
| Own collection + index/key | No | Yes | Parsers, lookup tables, selected items |
Rc/Arc indirection | Not internal self-reference | Yes |
Cheat Sheet
Core rule
A normal Rust struct generally cannot own a value and also store a reference into that same value.
Why
- owned values can be moved
- moving can change memory location
- references must always stay valid
- Rust prevents dangling internal references
Typical error meaning
"Does not live long enough" usually means:
- you created a reference to a local variable
- that local variable will be dropped too soon
- the reference would outlive the data it points to
Common failing pattern
struct Combined<'a> {
owner: Thing,
borrowed: &'a u32,
}
Common fixes
Store only the owner
struct Combined {
owner: Thing,
}
Borrow through a method
impl Combined {
fn borrowed(&self) -> &u32 {
&self.owner.count
}
}
Store a copied value
FAQ
Why can I return owned data but not a reference to local data?
Owned data is moved out of the function, so ownership transfers safely. A reference only points to data; it does not own it. If the referenced local data is dropped, the reference becomes invalid.
Does adding a lifetime parameter make the local variable live longer?
No. Lifetimes describe how long borrows are valid relative to other values. They do not extend the lifetime of local variables.
Why does this fail even when the second field is not written as &T?
Because the type may still contain a borrow internally, such as Child<'a>. Rust checks the actual borrowing relationships, not just surface syntax.
Can Box<T> solve this problem?
Not by itself. Box<T> puts data on the heap, but if you still try to store a reference into your own owned data in the same struct, you run into the same design issue.
Is there any way to build self-referential structs in Rust?
Yes, but it usually requires advanced techniques such as Pin, special crate support, or carefully controlled unsafe code. Most applications should prefer simpler designs.
What is the easiest alternative in beginner Rust?
Store the owned value and create references from &self methods when needed.
When should I use indexes instead of references?
Use indexes when the referenced data lives inside a collection owned by the same struct. This is very common in parsers, tokenizers, and data-processing code.
Mini Project
Description
Build a small Rust type that owns a string and tracks a selected word without storing a direct reference into itself. This demonstrates the Rust-friendly approach to replacing self-referential structs: store stable metadata like indexes, then derive references when needed.
Goal
Create a Document type that owns text, stores the start and end positions of a selected word, and returns that word as &str through a method.
Requirements
- Create a
Documentstruct that owns aString. - Store the selected word using start and end indexes, not a reference.
- Implement a constructor that finds the first word in the string.
- Add a method that returns the selected word as
Option<&str>. - Demonstrate the type in
mainby printing the selected word.
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.
Default Function Arguments in Rust: What to Use Instead
Learn how Rust handles default function arguments, why they are not supported, and practical patterns to achieve similar behavior.
Fixing Rust "linker 'cc' not found" on Debian in WSL
Learn why Rust shows "linker 'cc' not found" on Debian in WSL and how to fix it by installing the required C build tools.