In its current form, no this is not possible. First, let's deal with the parts of the problem we can control. If you want multiple different types to implement the same method, you don't define the method in the object's inherent impl; Instead, you define it in the trait. So if you want A::get and B::get to be related to the MyCollection trait, you need to write this.
pub trait MyCollection {
fn get<T>(&self) -> T;
}
pub struct A;
impl MyCollection for A {
fn get<T>(&self) -> T { ... }
}
pub struct B;
impl MyCollection for B {
fn get<T>(&self) -> T { ... }
}
Now the two get functions are related by the trait. We could write a function like this
fn get_as_int<C: MyCollection>(arg: &C) -> i32 {
arg.get::<i32>()
}
However, this is compile-time dispatch. While it's good for a lot of situations, it's not going to suffice if you want to store a heterogeneous collection of data.
In order to be able to use a trait MyCollection as a dyn MyCollection trait object, it must be object safe. These are some common sense sanity rules that make it possible for Rust to construct a vtable (virtual function table) for the type. Among them, each (dispatchable) method must satisfy
- Not have any type parameters (although lifetime parameters are allowed),
So your get<T> is right out, since it has a T type parameter. The reason for this is that Rust monomorphizes type parameters, so when you call get::<i32>(), Rust creates a new version of the get function which returns an i32. When Rust tries to make a trait object, it needs to create, in advance, all of the functions that could be called on the trait object and store them in the vtable. Since get<T> is actually an infinite class of functions, it can't ever do this, so we can't make trait objects.
If your intention is to have MyCollection store data of some type, whose type is known at compile-time (which is the most common way collections work), then you simply need to move the type argument to the trait level, not the function level. Your current trait
pub trait MyCollection {
fn get<T>(&self) -> T;
}
says "MyCollection is the type of objects for which, for any type T, I can get a T out of it". It's not really clear how you plan to usefully implement this trait. What if the collection stores a String and I ask to get::<u32>? Is that a panic?
Instead, consider
pub trait MyCollection<T> {
fn get(&self) -> T;
}
This says "MyCollection<T>, for some specific T, is a structure that I can get a T out of".
Now this get trait method doesn't have generic arguments, so the trait is object safe. We can store &dyn MyCollection<i32>, or Box<dyn MyCollection<i32>>, in a Vec<...> somewhere, because Rust only has to generate one method for the vtable. Then you would make Wrapper generic.
pub struct Wrapper<T> {
pub results: Vec<&dyn MyCollection<T>>,
}
The broad point here is, if you want to keep track of the type of something, you need to use a type variable to do it in the types themselves. Your type variable was declared too late and made a very strong promise. With this new trait, we always know the type of the collection at compile-time safely.