You can’t write a struct where one field holds a reference into another field of the same struct:

struct SelfRef {
    text: String,
    title: Option<&str>, // slice into `text` — won't compile
}

Why it’s forbidden (the semantic reason, not the syntax one): Rust values can move — stack↔heap, or to a new location on assignment/passing. A move relocates the whole struct, but an interior pointer would still hold the old address, now pointing at freed/garbage memory, and there’s no mechanism to fix up the pointer during the move. So the borrow checker refuses the construction. (The surface symptom is “missing lifetime specifier,” but the real issue is move-invalidation.)

Fixes:

  • Indices/ranges instead of references (e.g. title: Option<Range<usize>> into text). Offsets survive a move and are invisible to the borrow checker — but they become fragile pseudo-pointers that can go out of sync (same drawback as index-as-pointer designs).
  • Pin — pins a value in place, guaranteeing it never moves, so interior self-references stay valid. This is the primary motivation for Pin, which underpins async (a pending async block captures its environment and references into it — inherently self-referential).
  • Crates like ouroboros that encapsulate the difficulty.

General advice: avoid self-referential data structures; prefer owning data or restructure.

See also

References

Questions

flashcards/rust

Why can’t a Rust struct hold a reference into another of its own fields?::Values can move, relocating the struct; the interior pointer would still hold the old (now-invalid) address with no way to fix it up. So the borrow checker forbids it.

What are the two main ways to work around the need for a self-referential struct?::Store indices/ranges into the data (survive moves, invisible to the borrow checker but fragile), or use Pin to guarantee the value never moves (the motivation behind async).

Pin exists to pin a value in place so it never moves, keeping interior self-references valid — which is why it underpins async.