Mehdi Akiki
Rust Failure Atlas / Language and diagnostics

RFA-444 · Case file with fixtures · Case 416 of 694 · Compiler evidence

In a Rust Struct Pattern, the Real Field Goes Before the Colon

Struct pattern shorthand uses one identifier as both field and binding. To rename, write declared_field: local_name, such as y: z; reserve .. for intentional omission and let compiler errors expose schema drift.

Reviewed
Rust
Rust 1.98.1, edition 2024
Targets
all Rust targets
Profiles
dev, release, test

Direct answer

What this Rust failure means

Why it happens
Struct-pattern shorthand uses the same identifier as source field and local binding; renaming instead requires declared_field: local_name.
First discriminating check
Read the current struct declaration and put the declared field before the colon and the desired local name after it.

I wanted the y coordinate under a local name z and wrote Point { x, z }. Rust reported E0026 because the pattern asks Point for a field actually named z.

The failing fixture shows how shorthand can hide the mistake. There is no colon, so each identifier performs two roles: field selection and local binding with the same name.

Shorthand does not search by position

For named structs, Point { x, z } expands conceptually to:

Point { x: x, z: z }

Rust does not take the first listed field and then the next remaining field. Named patterns are independent of declaration order and require real field names.

The E0026 explanation points out that the identifier before a colon selects the struct field.

Rename with field: binding

The repaired fixture writes:

let Point { x, y: z } = point;

y is the declared source field. z is the new local binding. The assertion proves the local value came from the vertical coordinate.

In production I would usually choose vertical rather than z, unless the algorithm's mathematical notation makes the rename useful.

The colon direction matches construction syntax

Struct construction uses field: expression; struct patterns use field: subpattern. In both, the declared field is on the left.

This consistency helps me remember the direction. The right side can be a simple binding, wildcard, reference-related pattern, range, nested enum pattern, or binding @ subpattern.

The pattern is not a map from local names back to source names. It describes each source field and what must happen to its value.

E0026 can reveal schema drift

When a field was renamed or removed in a new dependency version, E0026 directs attention to patterns still using the old schema. The compiler may suggest a similarly named field, but I confirm semantic meaning before accepting it.

A replacement with the same type may represent a different concept. Tests should assert behaviour, not only compilation.

Generated code should derive field patterns from the same schema source as data definitions so renames remain coordinated.

Use .. only for deliberate omission

If I need only x, Point { x, .. } ignores every other field. This is useful and can make internal code resilient to added fields.

It can also hide a field that should influence logic after the structure evolves. For security and state-machine decisions, explicit field lists create valuable compiler pressure during changes.

I use .. when the operation truly depends on a subset, and I state that subset in tests.

Numeric fields belong to tuple structures

Tuple structs can be matched positionally. Their fields may be referred to with numeric syntax in some contexts, but ordinary tuple-struct pattern notation is usually clearer:

struct Point(i32, i32);
let Point(x, y) = point;

Changing a named struct to a tuple struct only to shorten patterns loses field labels throughout the API. I choose the data representation based on domain clarity.

Fixing the name can expose moves

If y contains a non-Copy value, binding it by value can partially move the struct. The syntax being correct does not mean the ownership choice is correct.

I match a reference or use appropriate binding forms when the original value must remain usable. The struct-pattern Reference explains shorthand and binding behaviour.

My E0026 checklist

I find this error most often after a data model rename. The consuming code may still use the old domain vocabulary even though the struct field changed. The repair can preserve that local vocabulary: new_field: old_local_name. That is useful during a migration, but I do not let it conceal a permanent mismatch accidentally. I search constructors, serializers, database mappings, and other destructuring sites before deciding whether only the pattern is stale or the model is divided between two names. A compiler error at one pattern can be the first visible clue of wider schema drift.

  • Does the left-side identifier exist in the current struct definition?
  • Was shorthand mistaken for a local rename?
  • Should the pattern say field: local?
  • Did a schema or dependency version rename the field?
  • Is a compiler suggestion semantically equivalent?
  • Should unneeded fields be explicit or covered by ..?
  • Will the corrected binding move data needed later?

The core principle is that named patterns follow source structure, not list position. The real field name goes before the colon, and the local pattern goes after it. Once I read the syntax in that direction, E0026 becomes a useful schema check rather than a mysterious destructuring error.