Can I initialize struct's generic type variable with specific type?

MyStruct implements MyTrait, can I initialize m: T with MyStruct ?
Expected code like this:

trait MyTrait {}
struct MyStruct {}

impl MyTrait for MyStruct{}

struct User<T: MyTrait> {
    m: T,
}

impl<T: MyTrait> Default for User<T> {
    fn default() -> Self {
        Self {
            m: MyStruct{},
        }
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/lib.rs:13:16
   |
10 | impl<T: MyTrait> Default for User<T> {
   |      - expected this type parameter
...
13 |             m: MyStruct{},
   |                ^^^^^^^^^^ expected type parameter `T`, found `MyStruct`
   |
   = note: expected type parameter `T`
                      found struct `MyStruct`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` (lib) due to 1 previous error

A generic T type argument is not a type chosen by you. It's always chosen by the caller. It's unknown from your perspective. It could be even a type that doesn't exist yet, and will be written in the future by someone else.

It does not behave like an abstract class that allows substituting for any implementation that is compatible. It behaves like a specific type, which is only compatible with itself, and is not any of your types.

You can make a non-generic implementation:

impl Default for User<MyStruct> {

or if MyTrait is "object safe", and you're ok with an extra allocation and run-time lookup, then:

impl Default for User<Box<dyn MyTrait>> {
    …
    Box::new(MyStruct{}) as Box<dyn MyTrait>

or you can skip MyTrait and MyStruct, and make a generic implementation that depends on another Default:

impl<D: Default> Default for User<D> {
    …
    Default::default()
5 Likes

Here's another pattern that's occasionally useful, if you're usually going to need boxed Users for some reason; it's got a much more niche use case than the others, though:

trait MyTrait {}
struct MyStruct {}

impl MyTrait for MyStruct{}

struct User<T: MyTrait + ?Sized = dyn MyTrait> {
    m: T,
}

impl Default for Box<User> {
    fn default() -> Self {
        Box::new(User { m: MyStruct{} })
    }
}
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.