RFA-443 · Case file with fixtures · Case 415 of 694 · Compiler evidence
A Struct Field Can Be Bound Only Once in One Pattern
Struct pattern labels identify source fields, while names after colons are local bindings. Each source field may appear once; fix a misspelled label, bind once and derive twice, or borrow according to the actual ownership need.
- 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
- Names left of pattern colons select source fields; two different local bindings do not permit that source field to be destructured twice.
- First discriminating check
- Expand shorthand, verify every left-side field name, and bind each source field only once before deriving any extra values.
I destructured a point and wrote the x field twice under two local names. Rust emitted E0025 because one struct field can be bound only once in a pattern.
The failing fixture uses Point { x: horizontal, x: vertical }. The likely human mistake is visible: the second source label should have been y.
The label before the colon selects the field
In a struct pattern:
Point { x: horizontal, y: vertical }
x and y are fields of Point. horizontal and vertical are new bindings in the arm or statement scope.
The E0025 explanation says each field can be bound only once. Changing the local name after the colon does not select a different source.
Most cases are a field-name typo
The repaired fixture changes the second label to y and asserts both values. This is the usual repair after copying one pattern entry and editing only its binding.
I compare the pattern with the struct declaration or language-server field completion. Similar field names such as source_id and target_id deserve tests with deliberately different values so a swap is visible.
Bind once when two calculations need one value
If both local concepts really derive from x, I bind it once:
let Point { x, .. } = point;
let horizontal = x;
let doubled = x * 2;
For a Copy number, duplication is straightforward. For a non-Copy field, I choose borrowing, cloning, shared ownership, or one ownership transfer according to the work.
A pattern cannot create two independent owned values from one non-Copy field merely by giving it two names.
Shorthand hides the two roles
Point { x, y } is shorthand for Point { x: x, y: y }. The field and local binding happen to share names.
Renaming syntax is useful when domain vocabulary at the use site differs from storage vocabulary. I keep the field label on the left and the local role on the right in review notes.
Multiple constraints belong in nested patterns
Sometimes I want to test a field and retain its complete value. The @ binding syntax can bind one value while applying a subpattern:
Point { x: horizontal @ 0..=10, .. }
This still selects x once. It expresses two uses through one pattern tree rather than two field entries.
Guards can apply additional runtime conditions after binding. I choose a subpattern when structural matching expresses the rule and a guard for calculations or external conditions.
Duplicate binding and duplicate local names differ
E0025 concerns one source field listed more than once. Another pattern error appears when the same local identifier is bound in incompatible places.
I read the diagnostic noun carefully: “field x bound multiple times” points to labels in a struct pattern. The fix is not always renaming the local variable; it is selecting each source component exactly once.
The struct-pattern Reference defines field patterns, shorthand, numeric tuple-struct fields, and the rest pattern.
Ownership remains after syntax is fixed
When a field is a String, name: local in a by-value pattern can move it. Other fields may still be borrowed or copied, producing partial-move rules.
If I need the whole struct later, I match on &point or borrow the field rather than adding clones automatically. Pattern correction and ownership design are two separate passes.
My E0025 checklist
The practical debugging trick is to rewrite all shorthand temporarily. A dense pattern such as Point { x, y: x } becomes clearer when I read it as two columns: the field selected on the left of each colon and the local binding introduced on the right. I then give each selected field one subpattern and do later calculations with the resulting bindings. This is especially useful in generated code or a large nested destructure, where the duplicated field can be far from the name collision that first catches my eye. After the ownership behaviour is correct, I can restore shorthand where it improves reading.
- Which labels are actual struct fields?
- Was one copied label supposed to name another field?
- Do tests give fields distinct values?
- Does one value need several derived calculations rather than several bindings?
- Would an
@subpattern express bind-and-test? - Will the fixed binding move a non-Copy field?
- Is shorthand hiding field-versus-local meaning?
The core principle is that destructuring partitions one source value. Each named struct field occupies one place in that partition and can be selected once. I bind it once, then explicitly borrow, copy, or derive whatever later computations need.