Skip to content

Commit 03cfc0a

Browse files
committed
Document destructuring assignment
1 parent 954f3d4 commit 03cfc0a

File tree

4 files changed

+118
-11
lines changed

4 files changed

+118
-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 expression](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

+76-5
Original file line numberDiff line numberDiff line change
@@ -428,13 +428,20 @@ 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
432+
*assignee operand*, followed by an equals sign (`=`) and a [value expression],
433+
the *assigned value operand*. In its most basic form, an assignee expression is
434+
a [place expression], and we discuss this case first. The more general case of
435+
destructuring assignment is discussed below, but this case always decomposes
436+
into sequential assignments to place expressions, which may be considered the
437+
more fundamental case.
432438

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.
439+
### Basic assignments
435440

436-
Evaluating assignment expressions begins by evaluating its operands.
437-
The assigned value operand is evaluated first, followed by the assigned place operand.
441+
Evaluating assignment expressions begins by evaluating its operands. The
442+
assigned value operand is evaluated first, followed by the assignee expression.
443+
(For destructuring assignment, subexpressions of the assignee expression are
444+
evaluated left-to-right.)
438445

439446
> **Note**: This is different than other expressions in that the right operand is evaluated before the left one.
440447
@@ -451,6 +458,67 @@ let y = 0;
451458
x = y;
452459
```
453460

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

456524
> **<sup>Syntax</sup>**\
@@ -530,6 +598,7 @@ See [this test] for an example of using this dependency.
530598
[logical xor]: ../types/boolean.md#logical-xor
531599
[mutable]: ../expressions.md#mutability
532600
[place expression]: ../expressions.md#place-expressions-and-value-expressions
601+
[assignee expression]: ../expressions.md#place-expressions-and-value-expressions
533602
[undefined behavior]: ../behavior-considered-undefined.md
534603
[unit]: ../types/tuple.md
535604
[value expression]: ../expressions.md#place-expressions-and-value-expressions
@@ -549,6 +618,8 @@ See [this test] for an example of using this dependency.
549618
[_TypeCastExpression_]: #type-cast-expressions
550619
[_AssignmentExpression_]: #assignment-expressions
551620
[_CompoundAssignmentExpression_]: #compound-assignment-expressions
621+
[_RangeExpression_]: #range-expressions
622+
[_UnderscoreExpression_]: #underscore-expression
552623

553624
[_Expression_]: ../expressions.md
554625
[_TypeNoBounds_]: ../types.md#type-expressions

src/expressions/underscore-expr.md

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

0 commit comments

Comments
 (0)