Search code examples
genericsrusttraits

Default generic type parameter not inferred in struct


I have a generic struct Test with a default generic type parameter implementing a trait. Here's my code:

pub trait Implementation {
    fn test();
}

pub struct FirstImpl;
impl Implementation for FirstImpl {
    fn test() {
        todo!()
    }
}

pub struct SecondImpl;

impl Implementation for SecondImpl {
    fn test() {
        todo!()
    }
}

pub struct Test<I: Implementation = FirstImpl> {
    _p: PhantomData<I>
}

impl <I: Implementation> Test <I> {
    pub fn new() -> Self {
       Self { _p: PhantomData }
    }
}



fn main() {
    let t = Test::new();

    let t2 = Test::<SecondImpl>::new();
}

Result:

error[E0282]: type annotations needed for `Test`
  --> src/main.rs:35:9
   |
35 |     let t = Test::new();
   |         ^
   |
help: consider giving `t` an explicit type, where the type for type parameter `I` is specified
   |
35 |     let t: Test<I> = Test::new();
   |          +++++++++

Playground

I've specified a default generic type parameter <I: Implementation = FirstImpl>, so I expect that when I create a Test instance without specifying the type parameter it will default to FirstImpl. However, I'm getting a compiler error that asks me to define the generic parameter I when calling new(). I thought the default type parameter would be inferred automatically. Am I missing something here?

Why isn't the default generic type parameter being inferred?


Solution

  • Why isn't the default generic type parameter being inferred?

    Because you've provided a new, unrelated, generic parameter to the impl block. As far as Rust is concerned there is no directly link between the <I: Implementation = FirstImpl> of the struct and the <I: Implementation> of the impl block. It's like declaring a function with a default parameter, then calling it with a parameter but refusing to state what that parameter is.

    You could leverage the default by having an

    impl Test {
        pub fn new() -> Self {
           Self { _p: PhantomData }
        }
    }
    

    although obviously the function is non-parametric, so you only get the default.