Using generic data structures with generic reference types
⚓ Rust 📅 2025-09-04 👤 surdeus 👁️ 10I'm trying to write a small library of generic data structures and algorithms in a way I hope to be as high-level/implementation-agnostic as possible. My reasoning: the less I constrain the implementations, the more reusable the code + test-cases, and the less code I need to change if I need to micro-optimize in the future.
I've been trying to use Rust's type system to my advantage here. Some examples of the traits I'm considering:
Map<K, V>: Maps keys of typeKto values of typeV(aHashMap<K, V>would trivially implement this trait)Set<T>: An unordered collection of values of typeT(aHashSet<T>would trivially implement this trait)
The interesting part comes down to references. For example, what should the type signature be for Map::get()? (I'm ignoring the self argument for now.)
- For
HashMap<K, V>: Map<K, V>it's usuallyfn(&K) -> &V - For
Vec<T>: Map<usize, T>it could befn(&usize) -> &Torfn(usize) -> &T - For a bitmap type, e.g.
BitMap: Map<usize, bool>, it really should befn(usize) -> bool(fn(&usize) -> boolmight work too), butfn(usize) -> &boolis too constraining since an efficient implementation usually uses something likeVec<u32>internally and thus can't return a&bool.
My solution here is to parameterize the reference types. For example the Map trait now becomes:
Map<K, V, KRef, VRef>: Data structure mappingKs toVs whose keys are referenced byKRefand whose values are referenced byVRef.Map::get()now has signaturefn(KRef) -> VRefand can be used for all scenarios described above. And as a bonus, a single data structure can implement multiple parameterizations ofMapdepending on the usage context.
Of course, now there's the issue of lifetimes. In the case of Map I arrived at this solution:
Map<'v, K, V, KRef, VRef>where'vdenotes the lifetime ofVRefMap::get()has signaturefn<'s>(KRef) -> VRef where 's: 'v.- An implementation requiring
VRef=&Vwould need to implementMap<'v, K, V, KRef, &'v V>.
This approach seems to work most of the time, although it does feel slightly hacky.
Here's my best attempt at implementing a generic unit test to the Set trait (this unfortunately fails with 2 lifetime errors): Rust Playground
Am I going down the right path here? Is there a better way to achieve the generality + flexibility I'm looking for that satisfies the borrow checker? Hoping I'm overlooking something simple here, e.g. perhaps my testing strategy is flawed more than anything else.
2 posts - 2 participants
🏷️ Rust_feed