Please explain ..self

Hi,

I came across ..self while trying to understand someone else's code. If I remove it a compiler error results stating missing struct fields. But I still not able to fully understanding it and cannot find any explanation yet.
Why .. before self? (range of all struct fields?) Please enlighten me! Thanks.

Given

struct User {
  id: UUID,
  name: String,
}

then you can create a value with a struct literal, as you know:

let bob = User {
  id: 1,
  name: "Bob, from Accounting",
};

but you can also create one by copying some fields from another value:

let doug = User {
  id: 2,
  ..bob,
};

This will create a User with id set to 2, but name (and all other fields) copied from bob.

Then ..self follows: it's copying the fields from self that are not otherwise being set.

5 Likes

See also this section in the book:

Creating Instances From Other Instances With Struct Update Syntax

It’s often useful to create a new instance of a struct that includes most of the values from another instance, but changes some. You can do this using struct update syntax.

First, in Listing 5-6 we show how to create a new User instance in user2 regularly, without the update syntax. We set a new value for email but otherwise use the same values from user1 that we created in Listing 5-2.

fn main() {
    // --snip--

    let user2 = User {
        active: user1.active,
        username: user1.username,
        email: String::from("another@example.com"),
        sign_in_count: user1.sign_in_count,
    };
}

Listing 5-6: Creating a new User instance using one of the values from user1

Using struct update syntax, we can achieve the same effect with less code, as shown in Listing 5-7. The syntax .. specifies that the remaining fields not explicitly set should have the same value as the fields in the given instance.

fn main() {
    // --snip--

    let user2 = User {
        email: String::from("another@example.com"),
        ..user1
    };
}

Listing 5-7: Using struct update syntax to set a new email value for a User instance but use the rest of the values from user1

The code in Listing 5-7 also creates an instance in user2 that has a different value for email but has the same values for the username, active, and sign_in_count fields from user1. The ..user1 must come last to specify that any remaining fields should get their values from the corresponding fields in user1, but we can choose to specify values for as many fields as we want in any order, regardless of the order of the fields in the struct’s definition.

Note that the struct update syntax uses = like an assignment; this is because it moves the data, just as we saw in the “Ways Variables and Data Interact: Move” section. In this example, we can no longer use user1 after creating user2 because the String in the username field of user1 was moved into user2. If we had given user2 new String values for both email and username, and thus only used the active and sign_in_count values from user1, then user1 would still be valid after creating user2. The types of active and sign_in_count are types that implement the Copy trait, so the behavior we discussed in the “Stack-Only Data: Copy” section would apply.

2 Likes

Thanks for code examples and the reference to the book, which I read through about half a year ago and apparently did not remember this feature.