Summary
If a generic constructor function appears in a struct expansion/update, it should be used to initialize the remaining variables using type inference.
Motivation
The classic generic in Option may not be Default and you have a lot of fields (e.g. in a generic builder)
#[derive(Default)]
struct Builder<T> {
a: Option<A>,
b: Option<B>,
t: Option<T>,
...
}
This (likely) doesn’t do what you want, because the derived impl requires T: Default, and instead you need:
impl<T> Default for Builder<T> {
fn default() -> Builder<T> {
a: Option::default(),
b: Option::default(),
t: Option::default(),
...
}
}
This gets unwieldy quickly.
Details
A generic constructor function is any function of the form:
fn foo<T>() -> T {
...
}
That is, a function with (at least) one generic argument, no args, and one return value of the expected type.
This definition is quite relaxed, and allows things like:
struct MyBuilder {
x: Option<Foo>,
y: Option<Bar>,
z: Baz
}
impl MyBuilder {
fn new() -> MyBuilder {
MyBuilder { z: Baz, .. Option::default }
}
}
Where Option::default takes one generic parameter T, and outputs an Option<T>. This compiles, because all fields (except z) are Option.
This syntax works because fn aren’t destructurable, and so the update syntax makes no sense for fn.
Alternatives
Do nothing.
Unresolved questions
Should it be possible to use multiple automatic initializers, if their bounds don’t overlap?
I’m supposed to write more here but idk what I’m missing.