mirror of https://github.com/rust-lang/reference
337 lines
16 KiB
Markdown
337 lines
16 KiB
Markdown
# Expressions
|
|
|
|
> **<sup>Syntax</sup>**\
|
|
> _Expression_ :\
|
|
> _ExpressionWithoutBlock_\
|
|
> | _ExpressionWithBlock_
|
|
>
|
|
> _ExpressionWithoutBlock_ :\
|
|
> [_OuterAttribute_]<sup>\*</sup>[†](#expression-attributes)\
|
|
> (\
|
|
> [_LiteralExpression_]\
|
|
> | [_PathExpression_]\
|
|
> | [_OperatorExpression_]\
|
|
> | [_GroupedExpression_]\
|
|
> | [_ArrayExpression_]\
|
|
> | [_AwaitExpression_]\
|
|
> | [_IndexExpression_]\
|
|
> | [_TupleExpression_]\
|
|
> | [_TupleIndexingExpression_]\
|
|
> | [_StructExpression_]\
|
|
> | [_CallExpression_]\
|
|
> | [_MethodCallExpression_]\
|
|
> | [_FieldExpression_]\
|
|
> | [_ClosureExpression_]\
|
|
> | [_AsyncBlockExpression_]\
|
|
> | [_ContinueExpression_]\
|
|
> | [_BreakExpression_]\
|
|
> | [_RangeExpression_]\
|
|
> | [_ReturnExpression_]\
|
|
> | [_UnderscoreExpression_]\
|
|
> | [_MacroInvocation_]\
|
|
> )
|
|
>
|
|
> _ExpressionWithBlock_ :\
|
|
> [_OuterAttribute_]<sup>\*</sup>[†](#expression-attributes)\
|
|
> (\
|
|
> [_BlockExpression_]\
|
|
> | [_UnsafeBlockExpression_]\
|
|
> | [_LoopExpression_]\
|
|
> | [_IfExpression_]\
|
|
> | [_IfLetExpression_]\
|
|
> | [_MatchExpression_]\
|
|
> )
|
|
|
|
An expression may have two roles: it always produces a *value*, and it may have *effects* (otherwise known as "side effects").
|
|
An expression *evaluates to* a value, and has effects during *evaluation*.
|
|
Many expressions contain sub-expressions, called the *operands* of the expression.
|
|
The meaning of each kind of expression dictates several things:
|
|
|
|
* Whether or not to evaluate the operands when evaluating the expression
|
|
* The order in which to evaluate the operands
|
|
* How to combine the operands' values to obtain the value of the expression
|
|
|
|
In this way, the structure of expressions dictates the structure of execution.
|
|
Blocks are just another kind of expression, so blocks, statements, expressions, and blocks again can recursively nest inside each other to an arbitrary depth.
|
|
|
|
> **Note**: We give names to the operands of expressions so that we may discuss them, but these names are not stable and may be changed.
|
|
|
|
## Expression precedence
|
|
|
|
The precedence of Rust operators and expressions is ordered as follows, going from strong to weak.
|
|
Binary Operators at the same precedence level are grouped in the order given by their associativity.
|
|
|
|
| Operator/Expression | Associativity |
|
|
|-----------------------------|---------------------|
|
|
| Paths | |
|
|
| Method calls | |
|
|
| Field expressions | left to right |
|
|
| Function calls, array indexing | |
|
|
| `?` | |
|
|
| Unary `-` `*` `!` `&` `&mut` | |
|
|
| `as` | left to right |
|
|
| `*` `/` `%` | left to right |
|
|
| `+` `-` | left to right |
|
|
| `<<` `>>` | left to right |
|
|
| `&` | left to right |
|
|
| `^` | left to right |
|
|
| <code>|</code> | left to right |
|
|
| `==` `!=` `<` `>` `<=` `>=` | Require parentheses |
|
|
| `&&` | left to right |
|
|
| <code>||</code> | left to right |
|
|
| `..` `..=` | Require parentheses |
|
|
| `=` `+=` `-=` `*=` `/=` `%=` <br> `&=` <code>|=</code> `^=` `<<=` `>>=` | right to left |
|
|
| `return` `break` closures | |
|
|
|
|
## Evaluation order of operands
|
|
|
|
The following list of expressions all evaluate their operands the same way, as described after the list.
|
|
Other expressions either don't take operands or evaluate them conditionally as described on their respective pages.
|
|
|
|
* Dereference expression
|
|
* Error propagation expression
|
|
* Negation expression
|
|
* Arithmetic and logical binary operators
|
|
* Comparison operators
|
|
* Type cast expression
|
|
* Grouped expression
|
|
* Array expression
|
|
* Await expression
|
|
* Index expression
|
|
* Tuple expression
|
|
* Tuple index expression
|
|
* Struct expression
|
|
* Call expression
|
|
* Method call expression
|
|
* Field expression
|
|
* Break expression
|
|
* Range expression
|
|
* Return expression
|
|
|
|
The operands of these expressions are evaluated prior to applying the effects of the expression.
|
|
Expressions taking multiple operands are evaluated left to right as written in the source code.
|
|
|
|
> **Note**: Which subexpressions are the operands of an expression is
|
|
> determined by expression precedence as per the previous section.
|
|
|
|
For example, the two `next` method calls will always be called in the same order:
|
|
|
|
```rust
|
|
# // Using vec instead of array to avoid references
|
|
# // since there is no stable owned array iterator
|
|
# // at the time this example was written.
|
|
let mut one_two = vec![1, 2].into_iter();
|
|
assert_eq!(
|
|
(1, 2),
|
|
(one_two.next().unwrap(), one_two.next().unwrap())
|
|
);
|
|
```
|
|
|
|
> **Note**: Since this is applied recursively, these expressions are also evaluated from innermost to outermost, ignoring siblings until there are no inner subexpressions.
|
|
|
|
## Place Expressions and Value Expressions
|
|
|
|
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], [dereferences][deref] (`*expr`), [array indexing] expressions (`expr[expr]`), [field] references (`expr.f`) and parenthesized place expressions.
|
|
All other expressions are value expressions.
|
|
|
|
A *value expression* is an expression that represents an actual value.
|
|
|
|
The following contexts are *place expression* contexts:
|
|
|
|
* The left operand of a [compound assignment] expression.
|
|
* The operand of a unary [borrow], [address-of][addr-of] or [dereference][deref] operator.
|
|
* The operand of a field expression.
|
|
* The indexed operand of an array indexing expression.
|
|
* The operand of any [implicit borrow].
|
|
* The initializer of a [let statement].
|
|
* The [scrutinee] of an [`if let`], [`match`][match], or [`while let`]
|
|
expression.
|
|
* The base of a [functional update] struct expression.
|
|
|
|
> 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 by value in a pattern, it denotes the value held _in_ that memory location.
|
|
If the type of that value implements [`Copy`], then the value will be copied.
|
|
In the remaining situations, if that type is [`Sized`], then it may be possible to move the value.
|
|
Only the following place expressions may be moved out of:
|
|
|
|
* [Variables] which are not currently borrowed.
|
|
* [Temporary values](#temporaries).
|
|
* [Fields][field] of a place expression which can be moved out of and don't implement [`Drop`].
|
|
* The result of [dereferencing][deref] an expression with type [`Box<T>`] and that can also be moved out of.
|
|
|
|
After moving out of a place expression that evaluates to a local variable, the location is deinitialized and cannot be read from again until it is reinitialized.
|
|
In all other cases, trying to use a place expression in a value expression context is an error.
|
|
|
|
### Mutability
|
|
|
|
For a place expression to be [assigned][assign] to, mutably [borrowed][borrow], [implicitly mutably borrowed], or bound to a pattern containing `ref mut`, it must be _mutable_.
|
|
We call these *mutable place expressions*.
|
|
In contrast, other place expressions are called *immutable place expressions*.
|
|
|
|
The following expressions can be mutable place expression contexts:
|
|
|
|
* Mutable [variables] which are not currently borrowed.
|
|
* [Mutable `static` items].
|
|
* [Temporary values].
|
|
* [Fields][field]: this evaluates the subexpression in a mutable place expression context.
|
|
* [Dereferences][deref] of a `*mut T` pointer.
|
|
* Dereference of a variable, or field of a variable, with type `&mut T`.
|
|
Note: This is an exception to the requirement of the next rule.
|
|
* Dereferences of a type that implements `DerefMut`:
|
|
this then requires that the value being dereferenced is evaluated in a mutable place expression context.
|
|
* [Array indexing] of a type that implements `IndexMut`:
|
|
this then evaluates the value being indexed, but not the index, in mutable place expression context.
|
|
|
|
### Temporaries
|
|
|
|
When using a value expression in most place expression contexts, a temporary unnamed memory location is created and initialized to that value.
|
|
The expression evaluates to that location instead, except if [promoted] to a `static`.
|
|
The [drop scope] of the temporary is usually the end of the enclosing statement.
|
|
|
|
### Implicit Borrows
|
|
|
|
Certain expressions will treat an expression as a place expression by implicitly borrowing it.
|
|
For example, it is possible to compare two unsized [slices][slice] for equality directly, because the `==` operator implicitly borrows its operands:
|
|
|
|
```rust
|
|
# let c = [1, 2, 3];
|
|
# let d = vec![1, 2, 3];
|
|
let a: &[i32];
|
|
let b: &[i32];
|
|
# a = &c;
|
|
# b = &d;
|
|
// ...
|
|
*a == *b;
|
|
// Equivalent form:
|
|
::std::cmp::PartialEq::eq(&*a, &*b);
|
|
```
|
|
|
|
Implicit borrows may be taken in the following expressions:
|
|
|
|
* Left operand in [method-call] expressions.
|
|
* Left operand in [field] expressions.
|
|
* Left operand in [call expressions].
|
|
* Left operand in [array indexing] expressions.
|
|
* Operand of the [dereference operator][deref] (`*`).
|
|
* Operands of [comparison].
|
|
* Left operands of the [compound assignment].
|
|
|
|
## Overloading Traits
|
|
|
|
Many of the following operators and expressions can also be overloaded for other types using traits in `std::ops` or `std::cmp`.
|
|
These traits also exist in `core::ops` and `core::cmp` with the same names.
|
|
|
|
## Expression Attributes
|
|
|
|
[Outer attributes][_OuterAttribute_] before an expression are allowed only in a few specific cases:
|
|
|
|
* Before an expression used as a [statement].
|
|
* Elements of [array expressions], [tuple expressions], [call expressions], and tuple-style [struct] expressions.
|
|
* The tail expression of [block expressions].
|
|
<!-- Keep list in sync with block-expr.md -->
|
|
|
|
They are never allowed before:
|
|
* [Range][_RangeExpression_] expressions.
|
|
* Binary operator expressions ([_ArithmeticOrLogicalExpression_], [_ComparisonExpression_], [_LazyBooleanExpression_], [_TypeCastExpression_], [_AssignmentExpression_], [_CompoundAssignmentExpression_]).
|
|
|
|
|
|
[block expressions]: expressions/block-expr.md
|
|
[call expressions]: expressions/call-expr.md
|
|
[field]: expressions/field-expr.md
|
|
[functional update]: expressions/struct-expr.md#functional-update-syntax
|
|
[`if let`]: expressions/if-expr.md#if-let-expressions
|
|
[match]: expressions/match-expr.md
|
|
[method-call]: expressions/method-call-expr.md
|
|
[paths]: expressions/path-expr.md
|
|
[struct]: expressions/struct-expr.md
|
|
[tuple expressions]: expressions/tuple-expr.md
|
|
[`while let`]: expressions/loop-expr.md#predicate-pattern-loops
|
|
|
|
[array expressions]: expressions/array-expr.md
|
|
[array indexing]: expressions/array-expr.md#array-and-slice-indexing-expressions
|
|
|
|
[assign]: expressions/operator-expr.md#assignment-expressions
|
|
[borrow]: expressions/operator-expr.md#borrow-operators
|
|
[addr-of]: expressions/operator-expr.md#raw-address-of-operators
|
|
[comparison]: expressions/operator-expr.md#comparison-operators
|
|
[compound assignment]: expressions/operator-expr.md#compound-assignment-expressions
|
|
[deref]: expressions/operator-expr.md#the-dereference-operator
|
|
|
|
[destructors]: destructors.md
|
|
[drop scope]: destructors.md#drop-scopes
|
|
|
|
[`Box<T>`]: ../std/boxed/struct.Box.html
|
|
[`Copy`]: special-types-and-traits.md#copy
|
|
[`Drop`]: special-types-and-traits.md#drop
|
|
[`Sized`]: special-types-and-traits.md#sized
|
|
[implicit borrow]: #implicit-borrows
|
|
[implicitly mutably borrowed]: #implicit-borrows
|
|
[interior mutability]: interior-mutability.md
|
|
[let statement]: statements.md#let-statements
|
|
[Mutable `static` items]: items/static-items.md#mutable-statics
|
|
[scrutinee]: glossary.md#scrutinee
|
|
[promoted]: destructors.md#constant-promotion
|
|
[slice]: types/slice.md
|
|
[statement]: statements.md
|
|
[static variables]: items/static-items.md
|
|
[Temporary values]: #temporaries
|
|
[Variables]: variables.md
|
|
|
|
[_ArithmeticOrLogicalExpression_]: expressions/operator-expr.md#arithmetic-and-logical-binary-operators
|
|
[_ArrayExpression_]: expressions/array-expr.md
|
|
[_AsyncBlockExpression_]: expressions/block-expr.md#async-blocks
|
|
[_AwaitExpression_]: expressions/await-expr.md
|
|
[_AssignmentExpression_]: expressions/operator-expr.md#assignment-expressions
|
|
[_BlockExpression_]: expressions/block-expr.md
|
|
[_BreakExpression_]: expressions/loop-expr.md#break-expressions
|
|
[_CallExpression_]: expressions/call-expr.md
|
|
[_ClosureExpression_]: expressions/closure-expr.md
|
|
[_ComparisonExpression_]: expressions/operator-expr.md#comparison-operators
|
|
[_CompoundAssignmentExpression_]: expressions/operator-expr.md#compound-assignment-expressions
|
|
[_ContinueExpression_]: expressions/loop-expr.md#continue-expressions
|
|
[_FieldExpression_]: expressions/field-expr.md
|
|
[_GroupedExpression_]: expressions/grouped-expr.md
|
|
[_IfExpression_]: expressions/if-expr.md#if-expressions
|
|
[_IfLetExpression_]: expressions/if-expr.md#if-let-expressions
|
|
[_IndexExpression_]: expressions/array-expr.md#array-and-slice-indexing-expressions
|
|
[_LazyBooleanExpression_]: expressions/operator-expr.md#lazy-boolean-operators
|
|
[_LiteralExpression_]: expressions/literal-expr.md
|
|
[_LoopExpression_]: expressions/loop-expr.md
|
|
[_MacroInvocation_]: macros.md#macro-invocation
|
|
[_MatchExpression_]: expressions/match-expr.md
|
|
[_MethodCallExpression_]: expressions/method-call-expr.md
|
|
[_OperatorExpression_]: expressions/operator-expr.md
|
|
[_OuterAttribute_]: attributes.md
|
|
[_PathExpression_]: expressions/path-expr.md
|
|
[_RangeExpression_]: expressions/range-expr.md
|
|
[_ReturnExpression_]: expressions/return-expr.md
|
|
[_StructExpression_]: expressions/struct-expr.md
|
|
[_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
|