Skip to content

Commit 8474309

Browse files
authored
Merge pull request #1116 from varkor/destructuring-assignment
Document destructuring assignment
2 parents 5e89e63 + 9b91e9b commit 8474309

File tree

6 files changed

+111
-11
lines changed

6 files changed

+111
-11
lines changed

src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
- [Match expressions](expressions/match-expr.md)
6767
- [Return expressions](expressions/return-expr.md)
6868
- [Await expressions](expressions/await-expr.md)
69+
- [Underscore expressions](expressions/underscore-expr.md)
6970

7071
- [Patterns](patterns.md)
7172

src/expressions.md

+22-6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
>       | [_BreakExpression_]\
2727
>       | [_RangeExpression_]\
2828
>       | [_ReturnExpression_]\
29+
>       | [_UnderscoreExpression_]\
2930
>       | [_MacroInvocation_]\
3031
>    )
3132
>
@@ -139,10 +140,11 @@ assert_eq!(
139140
140141
## Place Expressions and Value Expressions
141142

142-
Expressions are divided into two main categories: place expressions and
143-
value expressions. Likewise, within each expression, operands may occur
144-
in either place context or value context. The evaluation of an expression
145-
depends both on its own category and the context it occurs within.
143+
Expressions are divided into two main categories: place expressions and value
144+
expressions; there is also a third, minor category of expressions called
145+
assignee expressions. Within each expression, operands may likewise occur in
146+
either place context or value context. The evaluation of an expression depends
147+
both on its own category and the context it occurs within.
146148

147149
A *place expression* is an expression that represents a memory location. These
148150
expressions are [paths] which refer to local variables, [static variables],
@@ -154,8 +156,7 @@ A *value expression* is an expression that represents an actual value.
154156

155157
The following contexts are *place expression* contexts:
156158

157-
* The left operand of an [assignment][assign] or [compound assignment]
158-
expression.
159+
* The left operand of a [compound assignment] expression.
159160
* The operand of a unary [borrow] or [dereference][deref] operator.
160161
* The operand of a field expression.
161162
* The indexed operand of an array indexing expression.
@@ -168,6 +169,20 @@ The following contexts are *place expression* contexts:
168169
> Note: Historically, place expressions were called *lvalues* and value
169170
> expressions were called *rvalues*.
170171
172+
An *assignee expression* is an expression that appears in the left operand of an
173+
[assignment][assign] expression. Explicitly, the assignee expressions are:
174+
175+
- Place expressions.
176+
- [Underscores][_UnderscoreExpression_].
177+
- [Tuples][_TupleExpression_] of assignee expressions.
178+
- [Slices][_ArrayExpression_] of assingee expressions.
179+
- [Tuple structs][_StructExpression_] of assignee expressions.
180+
- [Structs][_StructExpression_] of assignee expressions (with optionally named
181+
fields).
182+
- [Unit structs][_StructExpression_].
183+
184+
Arbitrary parenthesisation is permitted inside assignee expressions.
185+
171186
### Moved and copied types
172187

173188
When a place expression is evaluated in a value expression context, or is bound
@@ -349,4 +364,5 @@ They are never allowed before:
349364
[_TupleExpression_]: expressions/tuple-expr.md
350365
[_TupleIndexingExpression_]: expressions/tuple-expr.md#tuple-indexing-expressions
351366
[_TypeCastExpression_]: expressions/operator-expr.md#type-cast-expressions
367+
[_UnderscoreExpression_]: expressions/underscore-expr.md
352368
[_UnsafeBlockExpression_]: expressions/block-expr.md#unsafe-blocks

src/expressions/operator-expr.md

+63-4
Original file line numberDiff line numberDiff line change
@@ -428,13 +428,15 @@ assert_eq!(values[1], 3);
428428
429429
An *assignment expression* moves a value into a specified place.
430430

431-
An assignment expression consists of a [mutable] [place expression], the *assigned place operand*, followed by an equals sign (`=`) and a [value expression], the *assigned value operand*.
431+
An assignment expression consists of a [mutable] [assignee expression], the *assignee operand*, followed by an equals sign (`=`) and a [value expression], the *assigned value operand*.
432+
In its most basic form, an assignee expression is a [place expression], and we discuss this case first.
433+
The more general case of destructuring assignment is discussed below, but this case always decomposes into sequential assignments to place expressions, which may be considered the more fundamental case.
432434

433-
Unlike other place operands, the assigned place operand must be a place expression.
434-
Attempting to use a value expression is a compiler error rather than promoting it to a temporary.
435+
### Basic assignments
435436

436437
Evaluating assignment expressions begins by evaluating its operands.
437-
The assigned value operand is evaluated first, followed by the assigned place operand.
438+
The assigned value operand is evaluated first, followed by the assignee expression.
439+
For destructuring assignment, subexpressions of the assignee expression are evaluated left-to-right.
438440

439441
> **Note**: This is different than other expressions in that the right operand is evaluated before the left one.
440442
@@ -451,6 +453,60 @@ let y = 0;
451453
x = y;
452454
```
453455

456+
### Destructuring assignments
457+
458+
Destructuring assignment is a counterpart to destructuring pattern matches for variable declaration, permitting assignment to complex values, such as tuples or structs.
459+
For instance, we may swap two mutable variables:
460+
461+
```rust
462+
let (mut a, mut b) = (0, 1);
463+
// Swap `a` and `b` using destructuring assignment.
464+
(b, a) = (a, b);
465+
```
466+
467+
In contrast to destructuring declarations using `let`, patterns may not appear on the left-hand side of an assignment due to syntactic ambiguities.
468+
Instead, a group of expressions that correspond to patterns are designated to be [assignee expressions][assignee expression], and permitted on the left-hand side of an assignment.
469+
Assignee expressions are then desugared to pattern matches followed by sequential assignment.
470+
The desugared patterns must be irrefutable: in particular, this means that only slice patterns whose length is known at compile-time, and the trivial slice `[..]`, are permitted for destructuring assignment.
471+
472+
The desugaring method is straightforward, and is illustrated best by example.
473+
474+
```rust
475+
# struct Struct { x: u32, y: u32 }
476+
# let (mut a, mut b) = (0, 0);
477+
(a, b) = (3, 4);
478+
479+
[a, b] = [3, 4];
480+
481+
Struct { x: a, y: b } = Struct { x: 3, y: 4};
482+
483+
// desugars to:
484+
485+
{
486+
let (_a, _b) = (3, 4);
487+
a = _a;
488+
b = _b;
489+
}
490+
491+
{
492+
let [_a, _b] = [3, 4];
493+
a = _a;
494+
b = _b;
495+
}
496+
497+
{
498+
let Struct { x: _a, y: _b } = Struct { x: 3, y: 4};
499+
a = _a;
500+
b = _b;
501+
}
502+
```
503+
504+
Identifiers are not forbidden from being used multiple times in a single assignee expression.
505+
506+
[Underscore expressions][_UnderscoreExpression_] and empty [range expressions][_RangeExpression_] may be used to ignore certain values, without binding them.
507+
508+
Note that default binding modes do not apply for the desugared expression.
509+
454510
## Compound assignment expressions
455511

456512
> **<sup>Syntax</sup>**\
@@ -530,6 +586,7 @@ See [this test] for an example of using this dependency.
530586
[logical xor]: ../types/boolean.md#logical-xor
531587
[mutable]: ../expressions.md#mutability
532588
[place expression]: ../expressions.md#place-expressions-and-value-expressions
589+
[assignee expression]: ../expressions.md#place-expressions-and-value-expressions
533590
[undefined behavior]: ../behavior-considered-undefined.md
534591
[unit]: ../types/tuple.md
535592
[value expression]: ../expressions.md#place-expressions-and-value-expressions
@@ -552,3 +609,5 @@ See [this test] for an example of using this dependency.
552609

553610
[_Expression_]: ../expressions.md
554611
[_TypeNoBounds_]: ../types.md#type-expressions
612+
[_RangeExpression_]: ./range-expr.md
613+
[_UnderscoreExpression_]: ./underscore-expr.md

src/expressions/underscore-expr.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# `_` expressions
2+
3+
> **<sup>Syntax</sup>**\
4+
> _UnderscoreExpression_ :\
5+
> &nbsp;&nbsp; `_`
6+
7+
Underscore expressions, denoted with the symbol `_`, are used to signify a
8+
placeholder in a destructuring assignment. They may only appear in the left-hand
9+
side of an assignment.
10+
11+
An example of an `_` expression:
12+
13+
```rust
14+
let p = (1, 2);
15+
let mut a = 0;
16+
(_, a) = p;
17+
```

src/macros-by-example.md

+6
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@ the syntax element that matched them. The keyword metavariable `$crate` can be
140140
used to refer to the current crate; see [Hygiene] below. Metavariables can be
141141
transcribed more than once or not at all.
142142

143+
For reasons of backwards compatibility, though `_` [is also an
144+
expression][_UnderscoreExpression_], a standalone underscore is not matched by
145+
the `expr` fragment specifier. However, `_` is matched by the `expr` fragment
146+
specifier when it appears as a subexpression.
147+
143148
> **Edition Differences**: Starting with the 2021 edition, `pat` fragment-specifiers match top-level or-patterns (that is, they accept [_Pattern_]).
144149
>
145150
> Before the 2021 edition, they match exactly the same fragments as `pat_param` (that is, they accept [_PatternNoTopAlt_]).
@@ -506,6 +511,7 @@ For more detail, see the [formal specification].
506511
[_Token_]: tokens.md
507512
[_TypePath_]: paths.md#paths-in-types
508513
[_Type_]: types.md#type-expressions
514+
[_UnderscoreExpression_]: expressions/underscore-expr.md
509515
[_Visibility_]: visibility-and-privacy.md
510516
[formal specification]: macro-ambiguity.md
511517
[token]: tokens.md

src/tokens.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ usages and meanings are defined in the linked pages.
582582
| `>=` | Ge | [Greater than or equal to][comparison], [Generics]
583583
| `<=` | Le | [Less than or equal to][comparison]
584584
| `@` | At | [Subpattern binding]
585-
| `_` | Underscore | [Wildcard patterns], [Inferred types], Unnamed items in [constants], [extern crates], and [use declarations]
585+
| `_` | Underscore | [Wildcard patterns], [Inferred types], Unnamed items in [constants], [extern crates], [use declarations], and [destructuring assignment]
586586
| `.` | Dot | [Field access][field], [Tuple index]
587587
| `..` | DotDot | [Range][range], [Struct expressions], [Patterns], [Range Patterns][rangepat]
588588
| `...` | DotDotDot | [Variadic functions][extern], [Range patterns]
@@ -625,6 +625,7 @@ them are referred to as "token trees" in [macros]. The three types of brackets
625625
[compound]: expressions/operator-expr.md#compound-assignment-expressions
626626
[constants]: items/constant-items.md
627627
[dereference]: expressions/operator-expr.md#the-dereference-operator
628+
[destructuring assignment]: expressions/underscore-expr.md
628629
[extern crates]: items/extern-crates.md
629630
[extern]: items/external-blocks.md
630631
[field]: expressions/field-expr.md

0 commit comments

Comments
 (0)