diff --git a/src/SUMMARY.md b/src/SUMMARY.md index fbbd43673..82d70d043 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -66,6 +66,7 @@ - [Match expressions](expressions/match-expr.md) - [Return expressions](expressions/return-expr.md) - [Await expressions](expressions/await-expr.md) + - [Underscore expressions](expressions/underscore-expr.md) - [Patterns](patterns.md) diff --git a/src/expressions.md b/src/expressions.md index 88f7fbac9..5b4092984 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -26,6 +26,7 @@ >       | [_BreakExpression_]\ >       | [_RangeExpression_]\ >       | [_ReturnExpression_]\ +>       | [_UnderscoreExpression_]\ >       | [_MacroInvocation_]\ >    ) > @@ -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], @@ -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. @@ -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 @@ -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 diff --git a/src/expressions/operator-expr.md b/src/expressions/operator-expr.md index 61df3bd64..d6fa4c23a 100644 --- a/src/expressions/operator-expr.md +++ b/src/expressions/operator-expr.md @@ -428,13 +428,15 @@ 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. +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. @@ -451,6 +453,60 @@ 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 +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][assignee expression], 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 +# struct Struct { x: u32, y: u32 } +# let (mut a, mut b) = (0, 0); +(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][_RangeExpression_] 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 > **Syntax**\ @@ -530,6 +586,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 @@ -552,3 +609,5 @@ See [this test] for an example of using this dependency. [_Expression_]: ../expressions.md [_TypeNoBounds_]: ../types.md#type-expressions +[_RangeExpression_]: ./range-expr.md +[_UnderscoreExpression_]: ./underscore-expr.md diff --git a/src/expressions/underscore-expr.md b/src/expressions/underscore-expr.md new file mode 100644 index 000000000..069f227e9 --- /dev/null +++ b/src/expressions/underscore-expr.md @@ -0,0 +1,17 @@ +# `_` expressions + +> **Syntax**\ +> _UnderscoreExpression_ :\ +>    `_` + +Underscore expressions, denoted with the symbol `_`, are used to signify a +placeholder in a destructuring assignment. They may only appear in the left-hand +side of an assignment. + +An example of an `_` expression: + +```rust +let p = (1, 2); +let mut a = 0; +(_, a) = p; +``` diff --git a/src/macros-by-example.md b/src/macros-by-example.md index f7e0ed4dd..da286a672 100644 --- a/src/macros-by-example.md +++ b/src/macros-by-example.md @@ -140,6 +140,11 @@ the syntax element that matched them. The keyword metavariable `$crate` can be used to refer to the current crate; see [Hygiene] below. Metavariables can be transcribed more than once or not at all. +For reasons of backwards compatibility, though `_` [is also an +expression][_UnderscoreExpression_], a standalone underscore is not matched by +the `expr` fragment specifier. However, `_` is matched by the `expr` fragment +specifier when it appears as a subexpression. + > **Edition Differences**: Starting with the 2021 edition, `pat` fragment-specifiers match top-level or-patterns (that is, they accept [_Pattern_]). > > 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]. [_Token_]: tokens.md [_TypePath_]: paths.md#paths-in-types [_Type_]: types.md#type-expressions +[_UnderscoreExpression_]: expressions/underscore-expr.md [_Visibility_]: visibility-and-privacy.md [formal specification]: macro-ambiguity.md [token]: tokens.md diff --git a/src/tokens.md b/src/tokens.md index 88a6d7252..5516fb7b3 100644 --- a/src/tokens.md +++ b/src/tokens.md @@ -582,7 +582,7 @@ usages and meanings are defined in the linked pages. | `>=` | Ge | [Greater than or equal to][comparison], [Generics] | `<=` | Le | [Less than or equal to][comparison] | `@` | At | [Subpattern binding] -| `_` | Underscore | [Wildcard patterns], [Inferred types], Unnamed items in [constants], [extern crates], and [use declarations] +| `_` | Underscore | [Wildcard patterns], [Inferred types], Unnamed items in [constants], [extern crates], [use declarations], and [destructuring assignment] | `.` | Dot | [Field access][field], [Tuple index] | `..` | DotDot | [Range][range], [Struct expressions], [Patterns], [Range Patterns][rangepat] | `...` | DotDotDot | [Variadic functions][extern], [Range patterns] @@ -625,6 +625,7 @@ them are referred to as "token trees" in [macros]. The three types of brackets [compound]: expressions/operator-expr.md#compound-assignment-expressions [constants]: items/constant-items.md [dereference]: expressions/operator-expr.md#the-dereference-operator +[destructuring assignment]: expressions/underscore-expr.md [extern crates]: items/extern-crates.md [extern]: items/external-blocks.md [field]: expressions/field-expr.md