Consider the following type family:
trait Throttler<Request> {
type Resource;
fn acquire(&self, req: Request) -> Self::Resource;
fn map<F, Resource>(self, f: F) -> Map<Self, F>
where
Self: Sized,
F: FnOnce(Self::Resource) -> Resource,
{
Map {
f,
inner: self,
}
}
}
pub struct Map<T, F> {
inner: T,
f: F,
}
impl<Request, T, F, Resource> Throttler<Request> for Map<T, F>
where
T: Throttler<Request>,
F: FnOnce(T::Resource) -> Resource + Clone,
{
type Resource = Resource;
fn acquire(&self, request: Request) -> Self::Resource {
(self.f.clone())(self.inner.acquire(request))
}
}
A Throttler
allows acquiring a given Resource
for some Request
type; it's possible to Map
a from one Resource
type to another.
Consider the following MyThrottler
type, which implements Throttler
for some generic Request
type, but with additional constraints:
struct MyThrottler { }
trait MyThrottlerRequest { }
impl<R: MyThrottlerRequest> Throttler<R> for MyThrottler<R> {
type Resource = ();
fn acquire(&self, req: R) -> Self::Resource { }
}
When using these types like so:
let t: Box<dyn Throttler<Req, Resource = Vec<()>>> = Box::new(MyThrottler { }.map(|_: ()| Vec::new()));
rustc
complains:
error[E0282]: type annotations needed
--> src/main.rs:56:82
|
56 | let t: Box<dyn Throttler<Req, Resource = Vec<()>>> = Box::new(MyThrottler {}.map(|_: ()| Vec::new()));
| ^^^
|
help: try using a fully qualified path to specify the expected types
|
56 | let t: Box<dyn Throttler<Req, Resource = Vec<()>>> = Box::new(<MyThrottler as Throttler<Request>>::map::<[closure@src/main.rs:56:86: 56:93], Vec<()>>(MyThrottler {}, |_: ()| Vec::new()));
This can be solved by adding a generic parameter to MyThrottler
, which requires using PhantomData
:
struct MyThrottler<R: MyThrottlerRequest> {
_marker: std::marker::PhantomData<R>,
}
Is there a more elegant way to get the compiler to infer the types without needing to use PhantomData
?