I have struct B
:
struct A {}
struct B {
a: A,
b: u32,
c: i8,
z: usize,
}
A
does not have a Default
implementation and no default that makes sense. The fields b
..z
all need to be initialised to the default (in this case, 0), and A
will be initialised to some runtime value:
let b = B {
a: some_a(),
b: 0,
c: 0,
z: 0,
};
This is not ideal.
Even worse, if an aa
were to be added to the struct, there would need to be another member added to the initialiser. Using ..Default::default()
doesn't work because B
doesn't have a Default
implementation, because any A
s in the default will be too expensive to compute to simply throw away afterwards. Furthermore, I would need an extremely long struct initialiser in the Default
implementation anyway.
Is there any way to set the remaining struct members to their default values (so that b
would be set to the default of u32
) without writing all the member names out?
Preferably, there should be minimum change required to struct initialisers when new members are added. This means this is not ideal:
let b = B {
a: some_a(),
b: Default::default(),
c: Default::default(),
z: Default::default(),
};
If you have large structs, you can make your life easier by deriving a builder or a constructor function. There are a few crates that do this, and a popular one is derive_builder
.
Using that crate, you can do something like:
use derive_builder::Builder;
// this derive will generate a struct called BBuilder
#[derive(Builder)]
struct B {
a: A,
#[builder(default = "0")]
b: u32,
#[builder(default = "0")]
c: i8,
/* ... */
#[default(default = "0")]
z: usize
}
fn main() {
let a = A { ... };
// all default values for fields b..z
let b = BBuilder::default().a(a).build().unwrap();
// or specify just some of the fields
let b = BBuilder::default()
.a(a)
.c(42)
.z(255)
.build()
.unwrap();
}
Adding new fields to B
will not impact code that uses BBuilder
, as long as the fields have defaults. The downside is that you get a runtime panic if you miss a required field, rather than a compilation error.
Another crate is derive-new
, which is a bit simpler. You would use it like this:
use derive_new::new;
#[derive(new)]
struct B {
a: A,
#[new(default)]
b: u32,
#[new(default)]
c: i8,
/* ... */
#[new(default)]
z: usize
}
fn main() {
let a = A { ... };
// all default values for fields b..z
let b = B::new(a);
// To specify some of the default fields, you need to mutate
let mut b = B::new(a);
b.c = 42;
b.z = 255;
}
This doesn't generate any extra structs, it just adds a new
method, which takes all of the non-default arguments. It is a compilation error if you miss any non-default fields out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With