#[derive(Default)] vs ..default()

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