I'm trying to understand why the compiler can't infer which type should be returned, and why I have to explicitly define it. It's not that that's a big problem, just a little cumbersome and I'm certain it's that I'm doing something wrong.
I've got a type
T is a generic type parameter of the get function, which can be different from the type you've implemented the trait for. These might also compile (assuming the types in question implement FromWsm + for<'a> Deserialize<'a>)
let mut plans: Vec<String> = Plan::get(&client).await;
let mut plans: Vec<Vec<String>> = Plan::get(&client).await;
let mut plans: Vec<i32> = Plan::get(&client).await;
// and so on
If get is supposed to return the type the trait is implemented for, you need to use Self instead
I'm attempting to use default defintions of associated methods in the FromWsm trait to increase my code reuse.
{
let out = Plan::get(&client).await;
}
and I end up with the inverse of my previous issue
error[E0282]: type annotations needed
--> src/wsmservices2/plans.rs:336:30
|
336 | let out = Plan::get(&client).await;
| ^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `get`
|
help: consider specifying the generic argument
|
336 | let out = Plan::get::<T>(&client).await;
| +++++
where the compiler wants me (in my opinion) to overspecify, as the Plan::get::() seems quite excessive.
Just to be clear, I want to use an associated method (::url()) of the Plan type, while calling the associated default method from the FromWsm trait (::get()) and return instances of the Plan type.
This compiles successfully for me and the compiler can infer the returned type. I learned something new about how Self works today and I thank you both for it!
Yes, that's what I mean. The thing is, when you have a function that both takes and produces a concrete type, and doesn't depend on any other type for its operation, then it is not generic. It's just a plain old regular function where Self is a specific type. You might have directly used Plan in the signature as well.
Incidentally, Self is not magic, it is literally just the same thing as the type for which the impl is being written. Hence, if that type isn't generic, then Self isn't, either.
Note that a type isn't automatically generic just because you implement a trait for it. Generics use trait bounds for constraints to be at all usable, but traits impls don't change whether an already defined type itself is generic. These are two very different sides of the story. An impl provides a trait's concrete behavior on a type, while a generic bound constrains the set of types usable as the parameters of generic function/type.
I think that's where I got confused. My goal was to define one set of functions that would provide the same functionality for multiple Types. I was successful in doing that, but I wasn't actually using generics to do so.