I can add my own experience to complement @quindot's response.
Absolutely the latter! But we benefit from the ability to use data structures that are already written, tested, and battle hardened in production code. You want a linked list? std::collection::LinkedList
. You want a general purpose graph data structure? petgraph
. Etc. You probably don't have to write your own data structures. Most experienced Rustaceans wouldn't bother.
References are for temporarily referencing values that are owned elsewhere. That's it. If you try to stretch it more than that to using arbitrarily long lifetimes without very clear lifetime relationships, you are going to have a bad time.
The former solution might be perfectly acceptable in terms of maintenance cost and performance. If you really can gain more of either of these properties with references (maybe performance, but I doubt it would make your code easier to maintain), then you need to be mindful of where the values are actually owned in your graph-like data structures.
With an arena, it's usually just a big blob of memory owned by the root container and all children reference it: Arenas in Rust - In Pursuit of Laziness
Unfortunately, I don't think there is any one resource that will give you an adequate description of lifetimes in Rust without taking you through a whirlwind tour of category theory. My favorite references to return to infrequently are:
- Blog series: Lockout: Advanced aspects of lifetimes
- Common Rust Lifetime Misconceptions
- What is a good mental model for the borrow checker? - Lots of interesting and valuable information in this thread.
- Variance in Rust: An intuitive explanation - Ehsan's Blog
- And also the Subtyping and Variance chapter in the Nomicon.