Mehdi Akiki
Rust Failure Atlas / Language and diagnostics

RFA-445 · Case file with fixtures · Case 417 of 694 · Compiler evidence

A Struct Pattern Must Mention Every Field or Use ..

Rust makes omitted struct fields visible. Bind or ignore each field, or use .. to state that every remaining field is irrelevant; choose explicit coverage when schema evolution should force a review.

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
A struct pattern must account for its complete field shape unless .. explicitly states that all remaining fields are irrelevant.
First discriminating check
Decide whether omitted fields should be reviewed individually or deliberately ignored, then bind them, use field: _, or add one rest pattern.

I wanted only a record ID and wrote let Record { id } = record. Rust reported E0027 because the structure also has a payload field that the pattern did not mention.

The failing fixture makes omission visible at compile time. Rust requires the pattern either to account for every field or to state that a remainder is intentionally ignored.

Missing is different from ignored

A pattern describes the complete shape it matches. Leaving a field out accidentally could mean the developer forgot that data participates in the structure.

The E0027 explanation offers two repairs: include the field or add ...

This is not busywork. The choice records whether the field matters to the operation.

Use .. for an intentional subset

The repaired fixture writes:

let Record { id, .. } = record;

The rest pattern says zero or more unlisted fields may have any value. Only id is bound.

This is suitable for logging an identifier, routing by one field, or reading stable metadata while deliberately ignoring payload details.

.. appears at most once in the struct pattern because there is only one conceptual set of remaining fields.

Bind with _ when one ignored field deserves visibility

I can write payload: _ to mention one field without binding it. This makes the current shape explicit and causes a compile failure if another field is later added and not covered.

I can also write payload: _payload, but that creates a binding and may move the value. The leading underscore mainly suppresses an unused-variable warning; it does not behave like the wildcard.

For resource-owning fields, _ and _name can therefore have different lifecycle consequences.

Explicit coverage is a change detector

If a record represents authorization input, state transition data, or a signed message, a new field may require deliberate handling. Listing every field—binding useful ones and using _ for reviewed irrelevant ones—turns schema growth into compilation work.

Using .. opts out of that signal. I do it only when future fields should naturally remain irrelevant to this operation.

This is the struct equivalent of deciding between exhaustive enum arms and a wildcard.

Construction has another rule

.. in a pattern ignores remaining fields. ..base in a struct expression fills remaining fields from another value. These forms look related but have different direction and ownership effects.

I read whether the syntax is in expression or pattern position before reasoning about it.

Partial moves can follow the fix

Binding payload by value would move its String out of record, while copying id would not. The whole record could then become partially moved.

Using .. without binding payload does not move that ignored field. If the only explicit binding copies id, the original record can still remain usable. By contrast, binding a non-Copy field by value partially moves the record. If later use matters, I inspect every binding mode, destructure &record, or borrow selected fields.

I test the ownership behaviour needed after matching rather than assuming “ignored” means “the original variable stays usable.”

Public non-exhaustive structs add a crate boundary

External structs marked non-exhaustive require downstream patterns to include ... This permits the defining crate to add fields compatibly under that contract.

Inside my own data types, I can still choose explicit patterns to make internal evolution visible. API versioning and local review needs can differ.

The struct-pattern Reference defines named fields, numeric fields, shorthand, and the rest pattern.

My E0027 checklist

This distinction matters when I use a pattern as an API-change alarm. In parsing or authorization code, I often list reviewed fields explicitly because a new field may change meaning. In telemetry or display code, .. is often honest because unrelated future fields should not break the consumer. Neither form is universally safer. The safer form is the one that expresses how evolution should behave. E0027 forces that decision into code, where a future maintainer can see it, rather than leaving an omitted field to look like a typo or an assumption nobody documented.

  • Which fields are absent from the pattern?
  • Are they irrelevant by domain rule or merely forgotten?
  • Should future added fields trigger a compiler review?
  • Would field: _ document one ignored field better?
  • Does an underscore-prefixed binding accidentally move data?
  • Must the original structure remain usable afterward?
  • Is the type non-exhaustive across a crate boundary?

The core principle is that omission should be intentional. Rust does not silently erase fields from a structural pattern. I either account for them explicitly or write .. as a visible statement that every remainder field falls outside this operation's concern.