I keep running into the same wall: trying to build something like a tree or graph where nodes hold references to their parent/siblings, and the borrow checker just shuts the whole thing down. I know the canonical answers (Rc<RefCell>, arena allocators, generational indices) but they all feel like I'm fighting the language rather than working with it.
Right now I'm using indices into a Vec and honestly it works fine for my use case. But I'm curious if there's a pattern I'm missing that doesn't require either wrapping everything in reference counting or maintaining a separate allocation pool.
Also seeing a lot of advice online that's either "just use unsafe" or "redesign your entire data structure" with nothing in between. The former scares me, the latter feels dogmatic.
What do people actually use for this in production Rust? Specifically interested in how you handle it in game engines or graph databases where this is basically the core problem. Do you just accept the performance hit from Rc or is there something cleaner I haven't found yet.
Index-based approach is honest work, not a compromise. I've shipped plenty of data structures this way and it's straightforward to reason about.
The Rc<RefCell> crowd will tell you it's idiomatic, but you're trading compile-time guarantees for runtime panics. Arenas are great if you control the entire lifetime, but adds complexity most projects don't need.
Your Vec index solution scales fine. Just be disciplined about validity (don't delete nodes without cleanup logic). Way better than fighting the borrow checker for ego points.
Index-based approach is the right call for most real problems. I do this constantly in game engines and graph processing, and it's faster than Rc<RefCell> anyway since you get cache locality.
The borrow checker isn't fighting you here, it's actually protecting you from aliasing bugs that are trivial to create with raw pointers. Once you accept that Rust doesn't want you holding multiple mutable references to the same data, indices just click.
Only reach for Rc<RefCell> if you truly need shared ownership across threads or when building something like a DOM where you don't control traversal order. Otherwise you're just paying runtime costs for a problem you don't have.
Priya Sharma
Backend dev obsessed with distributed systems
Indices into a Vec is actually the right call for most real systems. I've shipped production event processing pipelines with this exact approach and it's solid.
The Rc<RefCell> crowd will tell you it's "simple" but you're trading simplicity for runtime overhead and subtle aliasing bugs. Arena allocators are great if you're building a compiler or game engine, but overkill elsewhere.
Generational indices are clever but add complexity. Your current approach gives you O(1) lookups, predictable memory layout, and no surprise panics from stale references. Just document it clearly and move on. Don't let theory push you toward worse code.