Rust impl default trait with private fields

It surprises me, because I'd think a common use-case would be to initialise a struct, and that some members of the struct would be private so you can hide implementation details behind and interface.

The problem is that the struct update syntax doesn't do what you think it does. For example, the book shows the following code:

let user2 = User {
    email: String::from("[email protected]"),
    username: String::from("anotherusername567"),
    ..user1
};

The ..user1 syntax fills in the User fields we haven't explicitly specified, such as active: user1.active, signin_count: user1.signin_count. .. may be followed by an arbitrary expression which returns the structure, which is where Default::default() comes into play, and means the same as User::default() because a User is expected. However, the desugaring remains unchanged and boils down to assigning individual fields, in neither case granting special access to private fields.

To get back to your example, this code:

let p = Point {
    z: 1,
    ..Default::default()
};

is syntactic sugar for:

let p = {
    let _tmp = Point::default();
    Point {
        x: _tmp.x,
        y: _tmp.y,
        z: 1,
    }
};

and not for the expected:

// NOT what happens
let p = {
    let _tmp = Point::default();
    p.z = 1;
    _tmp
};

What are my options here?

The most idiomatic option is to provide a builder for Point. That is also somewhat bulky1, so if you're looking for a simple solution, you could also use Point::default() and set the z attribute manually. The struct update syntax is incompatible with structs with private fields and just not useful for your type.


1 Though there are crates like derive_builder, typed-builder and builder-pattern that take some of the drudgery away.


What are my options here?

A new() with parameters or a builder.

..struct is just a convenient way of doing functional updates, it doesn't bypass ACLs. Here since your struct has private fields, users can not manipulate it as a "bare" struct, they have to treat it as a largely opaque type.