---
title: "10.3 Field init shorthand and update syntax"
description: "Field init shorthand removes repetition when a variable already shares a field's name, and struct update syntax builds a new instance from an existing one."
url: "https://learnrust.net/chapter-10/field-init-and-update-syntax/"
last_updated: "2026-06-13"
---

# 10.3 Field init shorthand and update syntax

Building instances by hand gets repetitive fast. Rust has two small pieces of syntax that remove the most common repetitions. Neither adds a new idea; both just save typing and, more importantly, save you from a class of copy-paste mistakes.

## Field init shorthand

A struct is often built inside a function whose parameters already have the field names. That's no accident: when you name a function parameter `email`, it's because it holds an email. Written out the long way, the pattern looks silly:

```rust
struct User {
    name: String,
    email: String,
    active: bool,
}

fn build_user(name: String, email: String) -> User {
    User {
        name: name,
        email: email,
        active: true,
    }
}
```

`name: name` and `email: email` say the same word twice: the field `name` gets the value of the variable `name`. Rust lets you write the name once when the field and the variable match. This is **field init shorthand**:

```rust
fn build_user(name: String, email: String) -> User {
    User {
        name,
        email,
        active: true,
    }
}
```

`name` on its own means `name: name`. Fields whose value comes from somewhere else (`active: true`) are written out as usual. The shorthand only applies when an in-scope variable has exactly the field's name; otherwise you spell out the value. Clippy will nudge you toward the shorthand if you write the redundant form, so this is the version you'll see in real code.

> **Best practice**
>
> Use field init shorthand whenever a variable already carries the field's name. Beyond saving keystrokes, it removes the mismatched-pair bug: with `name: name, email: email` written out, a tired copy-paste produces `name: name, email: name`, and both are `String` so the compiler can't object. The shorthand simply can't express that mistake.

## Struct update syntax

The other repetition is "give me one just like this, but change a field or two." Suppose you have a user and want a copy with `active` flipped:

```rust
fn main() {
    let user1 = User {
        name: String::from("Ada"),
        email: String::from("ada@example.com"),
        active: true,
    };

    let user2 = User {
        name: user1.name,
        email: user1.email,
        active: false,
    };
}
```

Copying every unchanged field by hand is exactly the noise structs were supposed to remove. **Struct update syntax** says "the rest comes from that one" with `..`:

```rust
    let user2 = User {
        active: false,
        ..user1
    };
```

The fields you list (`active: false`) are set explicitly; `..user1` fills in *every remaining field* from `user1`. The `..base` part comes last and has no trailing comma. Read it as "and the rest, from `user1`."

## What moves when you update

The `..` is convenient, but it is not free, and chapter 8 already taught you the reason to look twice. Struct update *moves* the fields it copies, unless they're `Copy`. After the `user2` line above, `user1.name` and `user1.email` have been moved into `user2`, so `user1` is partly gutted. Using it triggers a familiar refusal:

```rust
    let user2 = User { active: false, ..user1 };
    println!("{}", user1.name);
```

```
error[E0382]: borrow of moved value: `user1.name`
 --> src/main.rs:16:20
   |
14 |     let user2 = User { active: false, ..user1 };
   |                                       ------- value moved here
15 |
16 |     println!("{}", user1.name);
   |                    ^^^^^^^^^^ value borrowed here after move
```

This is lesson [8.4](https://learnrust.net/chapter-8/moves/)'s move and lesson [8.6](https://learnrust.net/chapter-8/ownership-and-functions/)'s "this function took it" beat, now applied field by field. `String` isn't `Copy` (it owns heap text, lesson [8.5](https://learnrust.net/chapter-8/copy-types/)), so `..user1` moves the strings out, and the moved-from `user1` can't be read. Fields that *are* `Copy`, like the `bool` `active`, would be copied instead and leave the source intact. If `user2` had reused only `active` and supplied its own name and email, `user1` would survive whole.

> **Key insight**
>
> `..base` isn't a snapshot; it's a per-field move (or copy, for `Copy` fields). The same rule you learned for `let s2 = s1;` applies inside struct update, one field at a time. If you need both instances to keep using a heap-owning field, `.clone()` it explicitly (lesson [8.7](https://learnrust.net/chapter-8/clone/)) rather than reaching for `..`.

## Quiz time

**Question #1**

Rewrite this using field init shorthand:

```rust
fn make_point(x: f64, y: f64) -> Point {
    Point { x: x, y: y }
}
```

<details class="solution">
<summary>Show solution</summary>

```rust
fn make_point(x: f64, y: f64) -> Point {
    Point { x, y }
}
```

Both fields match an in-scope variable name, so both collapse to the bare name.

</details>

**Question #2**

Given `user1` from this lesson, what does struct update produce, and what happens to `user1` afterward?

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

<details class="solution">
<summary>Show solution</summary>

`user2` gets the supplied `email` and takes `name` and `active` from `user1`. `name` is a `String`, so it's *moved* out of `user1`; `active` is a `bool` (`Copy`) and is copied. Afterward `user1` can't be used as a whole, and `user1.name` specifically is moved-out, so reading it is E0382. Reading `user1.active` would still be fine, since only the moved fields are off-limits.

</details>

**Question #3**

Why does field init shorthand prevent a bug that the written-out form allows?

<details class="solution">
<summary>Show solution</summary>

The written-out form `name: name, email: email` repeats each name, so a copy-paste slip can produce `name: name, email: name`, which compiles whenever the two fields share a type. The shorthand writes each name once; there's no second copy to get wrong, so the mismatch is simply unwritable.

</details>

So far structs have had named fields. The next lesson covers two leaner variants: tuple structs, whose fields are numbered, and unit structs, which have no fields at all but still earn their keep.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
