I recently needed to initialize a bindgen-generated struct with lots of fields. It doesn’t derive Default because it’s unnecessary for most structs in FFI layer, but I found that
let data = Data {
a: 10,
..Default::default()
}
Requires Data to impl Default. I would expect this only to be the case for Data::default()
but with partial initialization why does rustc put this requirement on the struct? Shouldn’t it just check if the actual fields implement Default and not the whole struct? Is there a reason for that? It would be handy to have this working.
Thanks.
..{expression}
in this context doesn't look at individual fields. Instead, the expression can be anything that's the same type as the containing struct -- in this case Data
. So you could do this for example:
fn replace_a(other_data: Data) -> Data {
Data {
a: 10,
..other_data
}
}
So Default::default()
in your OP needs to produce a Data
. It is Data::default()
. (And there is no implementation of Default
for "some partial set of an arbitrary struct" that Default::default()
could otherwise resolve to.)
5 Likes
Default::default()
desugars to <_ as Default>::default()
, which inference figures out is <Data as Default>::default()
.
That's just a normal expression position -- you can do ..foo()
or whatever there too. There's nothing special about Default::default()
as the expression passed to FRU.
I do hope Rust will get a new feature to help with this case, though. Preferably the one that was discussed here:
4 Likes
I see. This syntax is a little ambiguous to read. I can now read it both ways and they both make sense, so not sure which one sounds more precise: “Use default values for the fields from the Default impl of the struct” OR “ Use the default values for the fields independent of the struct’s Default impl” .
Thanks!
This is the one that's correct. Notably, the default for the b
field in Data
might be 12345
, even though it's an i32
(which has <i32 as Default>::default() == 0
).
If it helps,
let data = Data {
a: 10,
..Default::default()
};
Is the same as
let data_defaults: Data = Default::default();
let data = Data {
a: 10,
..data_defaults
};
2 Likes