I am trying to write a trait describing a client for an HTTP server where I can tie the response to the query type:
trait Query {
type Output;
}
trait ApiClient {
fn send<Q: Query>(&self, q: &Q) -> Q::Output
where
Self: Sized;
}
I am able to write and use it when it is implemented for a type known at compile time. However I would like to use it from a trait object:
fn test_api_client(client: &dyn ApiClient) {
impl Query for u32 {
type Output = u32;
}
let query: u32 = 10;
let output = client.send(&query);
dbg!(output);
}
The playground code fails with the following error:
error: the `send` method cannot be invoked on a trait object
--> src/main.rs:38:23
|
12 | Self: Sized;
| ----- this has a `Sized` requirement
...
38 | let output = client.send(&query);
| ^^^^
Is there a workaround to wrap this generic method so it can be used through a trait object? I tried implementing it on &T
where T: ApiClient
because &dyn ApiClient
is sized even if dyn ApiClient
is not but wasn't able to use it.
I found that I can use Iterator::map
through a trait object, despite this method being generic:
fn test(it: &mut dyn Iterator<Item = u8>) {
for i in it.map(|x| x + 1) {
dbg!(i);
}
}
This is the Iterator::map
implementation:
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn map<B, F>(self, f: F) -> Map<Self, F>
where
Self: Sized,
F: FnMut(Self::Item) -> B,
{
Map::new(self, f)
}
How can I achieve a similar result as the standard library for Iterator
?