Skip to content

Commit e048dfc

Browse files
committed
Document destructuring assignment
1 parent 954f3d4 commit e048dfc

File tree

4 files changed

+117
-11
lines changed

4 files changed

+117
-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

+75-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,66 @@ 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], and permitted on the left-hand side of an assignment. Assignee
477+
expressions are then desugared to pattern matches followed by sequential
478+
assignment. The desugared patterns must be irrefutable: in particular, this
479+
means that only slice patterns whose length is known at compile-time, and the
480+
trivial slice `[..]`, are permitted for destructuring assignment.
481+
482+
The desugaring method is straightforward, and is illustrated best by example.
483+
484+
```rust,ignore
485+
(a, b) = (3, 4);
486+
487+
[a, b] = [3, 4];
488+
489+
Struct { x: a, y: b } = Struct { x: 3, y: 4};
490+
491+
// desugars to:
492+
493+
{
494+
let (_a, _b) = (3, 4);
495+
a = _a;
496+
b = _b;
497+
}
498+
499+
{
500+
let [_a, _b] = [3, 4];
501+
a = _a;
502+
b = _b;
503+
}
504+
505+
{
506+
let Struct { x: _a, y: _b } = Struct { x: 3, y: 4};
507+
a = _a;
508+
b = _b;
509+
}
510+
```
511+
512+
Identifiers are not forbidden from being used multiple times in a single
513+
assignee expression.
514+
515+
[Underscore expressions][_UnderscoreExpression_] and empty [range
516+
expressions](_RangeExpressions_) may be used to ignore certain values, without
517+
binding them.
518+
519+
Note that default binding modes do not apply for the desugared expression.
520+
454521
## Compound assignment expressions
455522

456523
> **<sup>Syntax</sup>**\
@@ -530,6 +597,7 @@ See [this test] for an example of using this dependency.
530597
[logical xor]: ../types/boolean.md#logical-xor
531598
[mutable]: ../expressions.md#mutability
532599
[place expression]: ../expressions.md#place-expressions-and-value-expressions
600+
[assignee expression]: ../expressions.md#place-expressions-and-value-expressions
533601
[undefined behavior]: ../behavior-considered-undefined.md
534602
[unit]: ../types/tuple.md
535603
[value expression]: ../expressions.md#place-expressions-and-value-expressions
@@ -549,6 +617,8 @@ See [this test] for an example of using this dependency.
549617
[_TypeCastExpression_]: #type-cast-expressions
550618
[_AssignmentExpression_]: #assignment-expressions
551619
[_CompoundAssignmentExpression_]: #compound-assignment-expressions
620+
[_RangeExpression_]: #range-expressions
621+
[_UnderscoreExpression_]: #underscore-expression
552622

553623
[_Expression_]: ../expressions.md
554624
[_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)