I have a trait
pub trait FromContext {
fn from_context<T>(context: Context<T>) -> Result<Self>;
}
and I would like to have an implementation of that trait like this
pub struct State<T>(pub T);
impl<T> FromContext for State<T> {
fn from_context<T>(context: Context<T>) -> Result<Self> {
Result::Ok(State(context.state))
}
}
but I get the error
error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters
I also tried
impl<T1> FromContext for State<T1> {
fn from_context<T2>(context: Context<T2>) -> Result<Self> {
Result::Ok(State(context.state))
}
}
but then I get
error[E0308]: mismatched types
Is there anyway to tell Rust T1
and T2
should be equal?
pub trait FromContext {
fn from_context<T>(context: Context<T>) -> Result<Self>;
}
This trait's contract is that from_context
can be called with any possible T
whatsoever and this will produce a Result<Self>
. If instead you want only one T
to work, chosen by the implementation, you have two options.
First, you could use a generic trait. Just move the generic type parameter from the trait method to the trait itself.
pub trait FromContext<T> {
fn from_context(context: Context<T>) -> Result<Self>;
}
Now you can impl<T> FromContext<T> for State<T>
and all the types will line up. The benefit of this approach is that you can implement FromContext<T>
multiple times on the same type for different T
s.
(Sidebar: Given this definition, perhaps you can ditch your trait and instead use TryFrom<Context<T>>
?)
The second approach is to use associated types.
pub trait FromContext {
type ContextType;
fn from_context(context: Context<Self::ContextType>) -> Result<Self>;
}
This limits the number of implementations per type to one, but can be beneficial in other ways. In particular, blanket implementations involving generic traits such as FromContext<T>
can get tricky because types can implement this trait multiple times, whereas you don't have this problem with a non-generic FromContext
.
Implementing this trait would look like this:
impl<T> FromContext for State<T> {
type ContextType = T;
fn from_context<T>(context: Context<T>) -> Result<Self> {
Result::Ok(State(context.state))
}
}