Skip to content

Commit

Permalink
Document destructuring assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
varkor committed Dec 11, 2021
1 parent 954f3d4 commit e048dfc
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 11 deletions.
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
- [Match expressions](expressions/match-expr.md)
- [Return expressions](expressions/return-expr.md)
- [Await expressions](expressions/await-expr.md)
- [Underscore expression](expressions/underscore-expr.md)

- [Patterns](patterns.md)

Expand Down
28 changes: 22 additions & 6 deletions src/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
>       | [_BreakExpression_]\
>       | [_RangeExpression_]\
>       | [_ReturnExpression_]\
>       | [_UnderscoreExpression_]\
>       | [_MacroInvocation_]\
>    )
>
Expand Down Expand Up @@ -139,10 +140,11 @@ assert_eq!(
## Place Expressions and Value Expressions

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

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

The following contexts are *place expression* contexts:

* The left operand of an [assignment][assign] or [compound assignment]
expression.
* The left operand of a [compound assignment] expression.
* The operand of a unary [borrow] or [dereference][deref] operator.
* The operand of a field expression.
* The indexed operand of an array indexing expression.
Expand All @@ -168,6 +169,20 @@ The following contexts are *place expression* contexts:
> Note: Historically, place expressions were called *lvalues* and value
> expressions were called *rvalues*.
An *assignee expression* is an expression that appears in the left operand of an
[assignment][assign] expression. Explicitly, the assignee expressions are:

- Place expressions.
- [Underscores][_UnderscoreExpression_].
- [Tuples][_TupleExpression_] of assignee expressions.
- [Slices][_ArrayExpression_] of assingee expressions.
- [Tuple structs][_StructExpression_] of assignee expressions.
- [Structs][_StructExpression_] of assignee expressions (with optionally named
fields).
- [Unit structs][_StructExpression_].

Arbitrary parenthesisation is permitted inside assignee expressions.

### Moved and copied types

When a place expression is evaluated in a value expression context, or is bound
Expand Down Expand Up @@ -349,4 +364,5 @@ They are never allowed before:
[_TupleExpression_]: expressions/tuple-expr.md
[_TupleIndexingExpression_]: expressions/tuple-expr.md#tuple-indexing-expressions
[_TypeCastExpression_]: expressions/operator-expr.md#type-cast-expressions
[_UnderscoreExpression_]: expressions/underscore-expr.md
[_UnsafeBlockExpression_]: expressions/block-expr.md#unsafe-blocks
80 changes: 75 additions & 5 deletions src/expressions/operator-expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -428,13 +428,20 @@ assert_eq!(values[1], 3);
An *assignment expression* moves a value into a specified place.

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*.
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*. In its most basic form, an assignee expression is
a [place expression], and we discuss this case first. 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.

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

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

> **Note**: This is different than other expressions in that the right operand is evaluated before the left one.
Expand All @@ -451,6 +458,66 @@ let y = 0;
x = y;
```

### Destructuring assignments

Destructuring assignment is a counterpart to destructuring pattern matches for
variable declaration, permitting assignment to complex values, such as tuples or
structs. For instance, we may swap two mutable variables:

```rust,ignore
let (mut a, mut b) = (0, 1);
// Swap `a` and `b` using destructuring assignment.
(b, a) = (a, b);
```

In contrast to destructuring declarations using `let`, patterns may not appear
on the left-hand side of an assignment due to syntactic ambiguities. Instead, a
group of expressions that correspond to patterns are designated to be [assignee
expressions], and permitted on the left-hand side of an assignment. Assignee
expressions are then desugared to pattern matches followed by sequential
assignment. 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.

The desugaring method is straightforward, and is illustrated best by example.

```rust,ignore
(a, b) = (3, 4);
[a, b] = [3, 4];
Struct { x: a, y: b } = Struct { x: 3, y: 4};
// desugars to:
{
let (_a, _b) = (3, 4);
a = _a;
b = _b;
}
{
let [_a, _b] = [3, 4];
a = _a;
b = _b;
}
{
let Struct { x: _a, y: _b } = Struct { x: 3, y: 4};
a = _a;
b = _b;
}
```

Identifiers are not forbidden from being used multiple times in a single
assignee expression.

[Underscore expressions][_UnderscoreExpression_] and empty [range
expressions](_RangeExpressions_) may be used to ignore certain values, without
binding them.

Note that default binding modes do not apply for the desugared expression.

## Compound assignment expressions

> **<sup>Syntax</sup>**\
Expand Down Expand Up @@ -530,6 +597,7 @@ See [this test] for an example of using this dependency.
[logical xor]: ../types/boolean.md#logical-xor
[mutable]: ../expressions.md#mutability
[place expression]: ../expressions.md#place-expressions-and-value-expressions
[assignee expression]: ../expressions.md#place-expressions-and-value-expressions
[undefined behavior]: ../behavior-considered-undefined.md
[unit]: ../types/tuple.md
[value expression]: ../expressions.md#place-expressions-and-value-expressions
Expand All @@ -549,6 +617,8 @@ See [this test] for an example of using this dependency.
[_TypeCastExpression_]: #type-cast-expressions
[_AssignmentExpression_]: #assignment-expressions
[_CompoundAssignmentExpression_]: #compound-assignment-expressions
[_RangeExpression_]: #range-expressions
[_UnderscoreExpression_]: #underscore-expression

[_Expression_]: ../expressions.md
[_TypeNoBounds_]: ../types.md#type-expressions
19 changes: 19 additions & 0 deletions src/expressions/underscore-expr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# `_` expression

> **<sup>Syntax</sup>**\
> _UnderscoreExpression_ :\
> &nbsp;&nbsp; `_`
The underscore expression, denoted with the symbol `_`, is used to signify a
placeholder in a destructuring assignment. It may only appear in the left-hand
side of an assignment.

An example of an `_` expression:

```rust,ignore
let p = (1, 2);
let mut a = 0;
(_, a) = p;
```

[_Expression_]: ../expressions.md

0 comments on commit e048dfc

Please sign in to comment.