Is it possible to do something like this in Rust?
trait Foo<T> {}
struct A;
struct B;
struct Bar<T: Foo> {
a: T<A>,
b: T<B>
}
I know I could just use two parameters for Bar
, but I think there has to be a better way to do this.
I want to implement a Graph
structure. As I can't just bind the nodes and edges to their parents lifetime, I want to have something like Rc
. However, sometimes one may need a Graph
with access from multiple threads. So I'd have to have both an implementation with Rc
and Arc
.
That's what Foo
is good for: I implement Foo
for both Rc
and Arc
(Foo
would require Deref
) and I use a parameter T
bound to Foo
. That's how I wanted to have one struct for single thread and multi thread usage.
You can use generic associated types (GATs) and the family pattern for that:
trait Family {
type Container<T>;
}
struct A;
struct B;
struct Bar<T: Family> {
a: T::Container<A>,
b: T::Container<B>,
}
Then you can define two families:
struct BoxFamily;
impl Family for BoxFamily {
type Container<T> = Box<T>;
}
struct VecFamily;
impl Family for VecFamily {
type Container<T> = Vec<T>;
}
And use it:
let boxes: Bar<BoxFamily> = Bar {
a: Box::new(A),
b: Box::new(B),
};
let vecs: Bar<VecFamily> = Bar {
a: vec![A, A],
b: vec![B],
};
As you can see, it's slightly more involved than one would hope for: you can't just say Bar<Vec>
for example, but have to go through the extra family type. But it works!
For an older answer (before GATs existed) containing more general information about the topic, click here.