I have a trait with a number of implementations that satisfy the common interface:
pub trait Schema<'a> {
// ConfigTypes will be parsed from HTTP POST requests, but different
// implementations can have different fields and know how to parse
// themselves
type ConfigType: rocket::request::FromForm<'a>
fn configure(&mut self, cfg: Self::Configure);
// and more...
}
Now imagine I want to implement a simple key/value store to map any number of these schemas from arbitrary strings. I feel like this should be possible with a HashMap, but what would the type be?
use std::collections::HashMap;
struct Datastore<'a> {
cache: HashMap<String, dyn Schema<'b>>
}
This fails complaining that the associated type ConfigType
must be specified, but I want to store any implementation of Schema
behind this cache!
I expected the problem is in irregular sizing, since the values of HashMap are expected to have static size. Alright then -- let's add Boxes to things.
// as above
struct Datastore<'a> {
cache: HashMap<String, Box<dyn Schema<'b>>>
}
but alas -- the same error presents. How do I define this structure to be able to hold any Schema implementer?
The associated type must be known. Otherwise how does the compiler know what type to use when you call methods that use that type?
There are a few ways around this:
Box<dyn Schema<ConfigType = &dyn rocket::request::FromForm<'b>, 'b>
You might have to implement rocket::request::FromForm<'b>
for &dyn rocket::request::FromForm<'b>
so it can downcast and pass it to the correct type.Box<dyn Any>
. Now you have to downcast it before you can use it.