Trait, struct and generics


#1

Is there a way to make this work?

pub trait Foo {
fn new() -> T { T { …Default::default()} }
}

where T would be some struct.
this fails to compile with “error: T does not name a structure”.


#2

I do not think you can do that with traits. A similar approach (but not a factory new() method) is to use Self. However, it does not look like you can make a default method for this in the trait because “Self” does not have a known size at compile time. The best you could do is to force its implementation on structs.

trait MyTrait {
    fn new() -> Self;
}

Also, to solve your issue, you could create a factory method, but I am not sure if this really does any more for you than calling MyStruct::new().

fn new<T>() -> T where T: Default {
    Default::default() 
}

See this code for more details.

Hope that helps.


#3

Your problem here is T is not a concrete type, but a type parameter, which can be pretty much anything, e.g. an enum, a struct, a trait object, whatever. So you just can’t instantiate something unknown as if it were a struct.
@wspowell already gave you working code, so I won’t repeat it. A possible variant can be:

trait MyTrait: Default {
    fn new() -> Self {
        Default::default()
    }
}

which is really doesn’t have much sense by itself, as you can just as well use Default::default() directly, unless you put some more complex logic in your new() method.


#4

I think it should be

fn new() -> Self where Self: Sized

because by default Self in a trait has ?Sized bound and so it can’t be returned from a function.