]>
Commit | Line | Data |
---|---|---|
8bb4bdeb XL |
1 | # Expressions |
2 | ||
8faf50e0 XL |
3 | > **<sup>Syntax</sup>**\ |
4 | > _Expression_ :\ | |
13cf67c4 XL |
5 | > _ExpressionWithoutBlock_\ |
6 | > | _ExpressionWithBlock_ | |
7 | > | |
8 | > _ExpressionWithoutBlock_ :\ | |
9 | > [_OuterAttribute_]<sup>\*</sup>[†](#expression-attributes)\ | |
10 | > (\ | |
11 | > [_LiteralExpression_]\ | |
12 | > | [_PathExpression_]\ | |
13 | > | [_OperatorExpression_]\ | |
14 | > | [_GroupedExpression_]\ | |
15 | > | [_ArrayExpression_]\ | |
e1599b0c | 16 | > | [_AwaitExpression_]\ |
13cf67c4 XL |
17 | > | [_IndexExpression_]\ |
18 | > | [_TupleExpression_]\ | |
19 | > | [_TupleIndexingExpression_]\ | |
20 | > | [_StructExpression_]\ | |
21 | > | [_EnumerationVariantExpression_]\ | |
22 | > | [_CallExpression_]\ | |
23 | > | [_MethodCallExpression_]\ | |
24 | > | [_FieldExpression_]\ | |
25 | > | [_ClosureExpression_]\ | |
26 | > | [_ContinueExpression_]\ | |
27 | > | [_BreakExpression_]\ | |
28 | > | [_RangeExpression_]\ | |
29 | > | [_ReturnExpression_]\ | |
30 | > | [_MacroInvocation_]\ | |
31 | > ) | |
32 | > | |
33 | > _ExpressionWithBlock_ :\ | |
34 | > [_OuterAttribute_]<sup>\*</sup>[†](#expression-attributes)\ | |
35 | > (\ | |
36 | > [_BlockExpression_]\ | |
e1599b0c | 37 | > | [_AsyncBlockExpression_]\ |
13cf67c4 XL |
38 | > | [_UnsafeBlockExpression_]\ |
39 | > | [_LoopExpression_]\ | |
40 | > | [_IfExpression_]\ | |
41 | > | [_IfLetExpression_]\ | |
42 | > | [_MatchExpression_]\ | |
43 | > ) | |
0531ce1d | 44 | |
8bb4bdeb XL |
45 | An expression may have two roles: it always produces a *value*, and it may have |
46 | *effects* (otherwise known as "side effects"). An expression *evaluates to* a | |
47 | value, and has effects during *evaluation*. Many expressions contain | |
48 | sub-expressions (operands). The meaning of each kind of expression dictates | |
49 | several things: | |
50 | ||
51 | * Whether or not to evaluate the sub-expressions when evaluating the expression | |
52 | * The order in which to evaluate the sub-expressions | |
7cac9316 XL |
53 | * How to combine the sub-expressions' values to obtain the value of the |
54 | expression | |
8bb4bdeb XL |
55 | |
56 | In this way, the structure of expressions dictates the structure of execution. | |
57 | Blocks are just another kind of expression, so blocks, statements, expressions, | |
58 | and blocks again can recursively nest inside each other to an arbitrary depth. | |
59 | ||
abe05a73 XL |
60 | ## Expression precedence |
61 | ||
62 | The precedence of Rust operators and expressions is ordered as follows, going | |
83c7162d XL |
63 | from strong to weak. Binary Operators at the same precedence level are grouped |
64 | in the order given by their associativity. | |
abe05a73 XL |
65 | |
66 | | Operator/Expression | Associativity | | |
67 | |-----------------------------|---------------------| | |
68 | | Paths | | | |
69 | | Method calls | | | |
70 | | Field expressions | left to right | | |
71 | | Function calls, array indexing | | | |
72 | | `?` | | | |
73 | | Unary `-` `*` `!` `&` `&mut` | | | |
83c7162d | 74 | | `as` | left to right | |
abe05a73 XL |
75 | | `*` `/` `%` | left to right | |
76 | | `+` `-` | left to right | | |
77 | | `<<` `>>` | left to right | | |
78 | | `&` | left to right | | |
79 | | `^` | left to right | | |
80 | | <code>|</code> | left to right | | |
81 | | `==` `!=` `<` `>` `<=` `>=` | Require parentheses | | |
82 | | `&&` | left to right | | |
83 | | <code>||</code> | left to right | | |
0531ce1d | 84 | | `..` `..=` | Require parentheses | |
abe05a73 XL |
85 | | `=` `+=` `-=` `*=` `/=` `%=` <br> `&=` <code>|=</code> `^=` `<<=` `>>=` | right to left | |
86 | | `return` `break` closures | | | |
87 | ||
ff7c6d11 | 88 | ## Place Expressions and Value Expressions |
8bb4bdeb | 89 | |
ff7c6d11 XL |
90 | Expressions are divided into two main categories: place expressions and |
91 | value expressions. Likewise within each expression, sub-expressions may occur | |
92 | in either place context or value context. The evaluation of an expression | |
93 | depends both on its own category and the context it occurs within. | |
8bb4bdeb | 94 | |
ff7c6d11 XL |
95 | A *place expression* is an expression that represents a memory location. These |
96 | expressions are [paths] which refer to local variables, [static variables], | |
532ac7d7 | 97 | [dereferences][deref] (`*expr`), [array indexing] expressions (`expr[expr]`), |
ff7c6d11 XL |
98 | [field] references (`expr.f`) and parenthesized place expressions. All other |
99 | expressions are value expressions. | |
8bb4bdeb | 100 | |
ff7c6d11 XL |
101 | A *value expression* is an expression that represents an actual value. |
102 | ||
532ac7d7 XL |
103 | The following contexts are *place expression* contexts: |
104 | ||
105 | * The left operand of an [assignment][assign] or [compound assignment] | |
106 | expression. | |
107 | * The operand of a unary [borrow] or [dereference][deref] operator. | |
108 | * The operand of a field expression. | |
109 | * The indexed operand of an array indexing expression. | |
110 | * The operand of any [implicit borrow]. | |
111 | * The initializer of a [let statement]. | |
112 | * The [scrutinee] of an [`if let`], [`match`][match], or [`while let`] | |
113 | expression. | |
114 | * The base of a [functional update] struct expression. | |
ff7c6d11 XL |
115 | |
116 | > Note: Historically, place expressions were called *lvalues* and value | |
117 | > expressions were called *rvalues*. | |
8bb4bdeb | 118 | |
7cac9316 | 119 | ### Moved and copied types |
8bb4bdeb | 120 | |
ff7c6d11 XL |
121 | When a place expression is evaluated in a value expression context, or is bound |
122 | by value in a pattern, it denotes the value held _in_ that memory location. If | |
123 | the type of that value implements [`Copy`], then the value will be copied. In | |
124 | the remaining situations if that type is [`Sized`], then it may be possible to | |
125 | move the value. Only the following place expressions may be moved out of: | |
7cac9316 | 126 | |
ff7c6d11 | 127 | * [Variables] which are not currently borrowed. |
7cac9316 | 128 | * [Temporary values](#temporary-lifetimes). |
ff7c6d11 XL |
129 | * [Fields][field] of a place expression which can be moved out of and |
130 | doesn't implement [`Drop`]. | |
532ac7d7 XL |
131 | * The result of [dereferencing][deref] an expression with type [`Box<T>`] and |
132 | that can also be moved out of. | |
7cac9316 | 133 | |
ff7c6d11 XL |
134 | Moving out of a place expression that evaluates to a local variable, the |
135 | location is deinitialized and cannot be read from again until it is | |
136 | reinitialized. In all other cases, trying to use a place expression in a value | |
137 | expression context is an error. | |
7cac9316 XL |
138 | |
139 | ### Mutability | |
140 | ||
ff7c6d11 XL |
141 | For a place expression to be [assigned][assign] to, mutably [borrowed][borrow], |
142 | [implicitly mutably borrowed], or bound to a pattern containing `ref mut` it | |
143 | must be _mutable_. We call these *mutable place expressions*. In contrast, | |
144 | other place expressions are called *immutable place expressions*. | |
7cac9316 | 145 | |
ff7c6d11 | 146 | The following expressions can be mutable place expression contexts: |
7cac9316 | 147 | |
ff7c6d11 XL |
148 | * Mutable [variables], which are not currently borrowed. |
149 | * [Mutable `static` items]. | |
150 | * [Temporary values]. | |
151 | * [Fields][field], this evaluates the subexpression in a mutable place | |
152 | expression context. | |
532ac7d7 | 153 | * [Dereferences][deref] of a `*mut T` pointer. |
7cac9316 | 154 | * Dereference of a variable, or field of a variable, with type `&mut T`. Note: |
ff7c6d11 | 155 | This is an exception to the requirement of the next rule. |
7cac9316 | 156 | * Dereferences of a type that implements `DerefMut`, this then requires that |
ff7c6d11 | 157 | the value being dereferenced is evaluated is a mutable place expression context. |
ea8adc8c | 158 | * [Array indexing] of a type that implements `DerefMut`, this |
ff7c6d11 XL |
159 | then evaluates the value being indexed, but not the index, in mutable place |
160 | expression context. | |
7cac9316 XL |
161 | |
162 | ### Temporary lifetimes | |
163 | ||
ff7c6d11 XL |
164 | When using a value expression in most place expression contexts, a temporary |
165 | unnamed memory location is created initialized to that value and the expression | |
166 | evaluates to that location instead, except if promoted to `'static`. Promotion | |
167 | of a value expression to a `'static` slot occurs when the expression could be | |
3b2f2976 | 168 | written in a constant, borrowed, and dereferencing that borrow where the |
0bf4aa26 XL |
169 | expression was originally written, without changing the runtime behavior. That |
170 | is, the promoted expression can be evaluated at compile-time and the resulting | |
171 | value does not contain [interior mutability] or [destructors] (these properties | |
172 | are determined based on the value where possible, e.g. `&None` always has the | |
173 | type `&'static Option<_>`, as it contains nothing disallowed). Otherwise, the | |
174 | lifetime of temporary values is typically | |
3b2f2976 | 175 | |
abe05a73 | 176 | - the innermost enclosing statement; the tail expression of a block is |
3b2f2976 | 177 | considered part of the statement that encloses the block, or |
abe05a73 | 178 | - the condition expression or the loop conditional expression if the |
ff7c6d11 XL |
179 | temporary is created in the condition expression of an `if` or in the loop |
180 | conditional expression of a `while` expression. | |
8bb4bdeb | 181 | |
ff7c6d11 XL |
182 | When a temporary value expression is being created that is assigned into a |
183 | [`let` declaration][let], however, the temporary is created with the lifetime of | |
184 | the enclosing block instead, as using the enclosing [`let` declaration][let] | |
185 | would be a guaranteed error (since a pointer to the temporary | |
7cac9316 XL |
186 | would be stored into a variable, but the temporary would be freed before the |
187 | variable could be used). The compiler uses simple syntactic rules to decide | |
188 | which values are being assigned into a `let` binding, and therefore deserve a | |
189 | longer temporary lifetime. | |
8bb4bdeb XL |
190 | |
191 | Here are some examples: | |
192 | ||
ff7c6d11 | 193 | - `let x = foo(&temp())`. The expression `temp()` is a value expression. As it |
8bb4bdeb | 194 | is being borrowed, a temporary is created which will be freed after |
ff7c6d11 | 195 | the innermost enclosing statement; in this case, the `let` declaration. |
8bb4bdeb XL |
196 | - `let x = temp().foo()`. This is the same as the previous example, |
197 | except that the value of `temp()` is being borrowed via autoref on a | |
198 | method-call. Here we are assuming that `foo()` is an `&self` method | |
199 | defined in some trait, say `Foo`. In other words, the expression | |
200 | `temp().foo()` is equivalent to `Foo::foo(&temp())`. | |
3b2f2976 | 201 | - `let x = if foo(&temp()) {bar()} else {baz()};`. The expression `temp()` is |
ff7c6d11 XL |
202 | a value expression. As the temporary is created in the condition expression |
203 | of an `if`, it will be freed at the end of the condition expression; | |
204 | in this example before the call to `bar` or `baz` is made. | |
abe05a73 | 205 | - `let x = if temp().must_run_bar {bar()} else {baz()};`. |
3b2f2976 XL |
206 | Here we assume the type of `temp()` is a struct with a boolean field |
207 | `must_run_bar`. As the previous example, the temporary corresponding to | |
208 | `temp()` will be freed at the end of the condition expression. | |
209 | - `while foo(&temp()) {bar();}`. The temporary containing the return value from | |
210 | the call to `temp()` is created in the loop conditional expression. Hence it | |
ff7c6d11 XL |
211 | will be freed at the end of the loop conditional expression; in this example |
212 | before the call to `bar` if the loop body is executed. | |
8bb4bdeb XL |
213 | - `let x = &temp()`. Here, the same temporary is being assigned into |
214 | `x`, rather than being passed as a parameter, and hence the | |
215 | temporary's lifetime is considered to be the enclosing block. | |
216 | - `let x = SomeStruct { foo: &temp() }`. As in the previous case, the | |
217 | temporary is assigned into a struct which is then assigned into a | |
218 | binding, and hence it is given the lifetime of the enclosing block. | |
219 | - `let x = [ &temp() ]`. As in the previous case, the | |
220 | temporary is assigned into an array which is then assigned into a | |
221 | binding, and hence it is given the lifetime of the enclosing block. | |
ff7c6d11 XL |
222 | - `let ref x = temp()`. In this case, the temporary is created using a ref |
223 | binding, but the result is the same: the lifetime is extended to the enclosing | |
224 | block. | |
8bb4bdeb | 225 | |
7cac9316 | 226 | ### Implicit Borrows |
8bb4bdeb | 227 | |
ff7c6d11 | 228 | Certain expressions will treat an expression as a place expression by implicitly |
b7449926 | 229 | borrowing it. For example, it is possible to compare two unsized [slices][slice] for |
ea8adc8c | 230 | equality directly, because the `==` operator implicitly borrows it's operands: |
7cac9316 XL |
231 | |
232 | ```rust | |
233 | # let c = [1, 2, 3]; | |
234 | # let d = vec![1, 2, 3]; | |
235 | let a: &[i32]; | |
236 | let b: &[i32]; | |
237 | # a = &c; | |
238 | # b = &d; | |
239 | // ... | |
240 | *a == *b; | |
241 | // Equivalent form: | |
242 | ::std::cmp::PartialEq::eq(&*a, &*b); | |
243 | ``` | |
244 | ||
245 | Implicit borrows may be taken in the following expressions: | |
246 | ||
ea8adc8c XL |
247 | * Left operand in [method-call] expressions. |
248 | * Left operand in [field] expressions. | |
249 | * Left operand in [call expressions]. | |
250 | * Left operand in [array indexing] expressions. | |
532ac7d7 | 251 | * Operand of the [dereference operator][deref] (`*`). |
ea8adc8c XL |
252 | * Operands of [comparison]. |
253 | * Left operands of the [compound assignment]. | |
7cac9316 | 254 | |
7cac9316 XL |
255 | ## Overloading Traits |
256 | ||
257 | Many of the following operators and expressions can also be overloaded for | |
ff7c6d11 | 258 | other types using traits in `std::ops` or `std::cmp`. These traits also |
7cac9316 | 259 | exist in `core::ops` and `core::cmp` with the same names. |
8bb4bdeb | 260 | |
13cf67c4 XL |
261 | ## Expression Attributes |
262 | ||
263 | [Outer attributes][_OuterAttribute_] before an expression are allowed only in | |
264 | a few specific cases: | |
265 | ||
266 | * Before an expression used as a [statement]. | |
267 | * Elements of [array expressions], [tuple expressions], [call expressions], | |
e1599b0c | 268 | and tuple-style [struct] and [enum variant] expressions. |
13cf67c4 XL |
269 | <!-- |
270 | These were likely stabilized inadvertently. | |
271 | See https://github.com/rust-lang/rust/issues/32796 and | |
272 | https://github.com/rust-lang/rust/issues/15701 | |
273 | --> | |
274 | * The tail expression of [block expressions]. | |
275 | <!-- Keep list in sync with block-expr.md --> | |
276 | ||
277 | They are never allowed before: | |
13cf67c4 XL |
278 | * [Range][_RangeExpression_] expressions. |
279 | * Binary operator expressions ([_ArithmeticOrLogicalExpression_], | |
280 | [_ComparisonExpression_], [_LazyBooleanExpression_], [_TypeCastExpression_], | |
281 | [_AssignmentExpression_], [_CompoundAssignmentExpression_]). | |
282 | ||
283 | ||
416331ca XL |
284 | [block expressions]: expressions/block-expr.md |
285 | [call expressions]: expressions/call-expr.md | |
286 | [enum variant]: expressions/enum-variant-expr.md | |
287 | [field]: expressions/field-expr.md | |
288 | [functional update]: expressions/struct-expr.md#functional-update-syntax | |
289 | [`if let`]: expressions/if-expr.md#if-let-expressions | |
290 | [match]: expressions/match-expr.md | |
291 | [method-call]: expressions/method-call-expr.md | |
292 | [paths]: expressions/path-expr.md | |
293 | [struct]: expressions/struct-expr.md | |
294 | [tuple expressions]: expressions/tuple-expr.md | |
295 | [`while let`]: expressions/loop-expr.md#predicate-pattern-loops | |
296 | ||
297 | [array expressions]: expressions/array-expr.md | |
298 | [array indexing]: expressions/array-expr.md#array-and-slice-indexing-expressions | |
299 | ||
300 | [assign]: expressions/operator-expr.md#assignment-expressions | |
301 | [borrow]: expressions/operator-expr.md#borrow-operators | |
302 | [comparison]: expressions/operator-expr.md#comparison-operators | |
303 | [compound assignment]: expressions/operator-expr.md#compound-assignment-expressions | |
304 | [deref]: expressions/operator-expr.md#the-dereference-operator | |
305 | ||
306 | [destructors]: destructors.md | |
307 | [interior mutability]: interior-mutability.md | |
308 | [`Box<T>`]: ../std/boxed/struct.Box.md | |
309 | [`Copy`]: special-types-and-traits.md#copy | |
310 | [`Drop`]: special-types-and-traits.md#drop | |
311 | [`Sized`]: special-types-and-traits.md#sized | |
ff7c6d11 XL |
312 | [implicit borrow]: #implicit-borrows |
313 | [implicitly mutably borrowed]: #implicit-borrows | |
416331ca XL |
314 | [let]: statements.md#let-statements |
315 | [let statement]: statements.md#let-statements | |
316 | [Mutable `static` items]: items/static-items.md#mutable-statics | |
317 | [scrutinee]: glossary.md#scrutinee | |
318 | [slice]: types/slice.md | |
319 | [statement]: statements.md | |
320 | [static variables]: items/static-items.md | |
ff7c6d11 | 321 | [Temporary values]: #temporary-lifetimes |
416331ca XL |
322 | [Variables]: variables.md |
323 | ||
324 | ||
325 | [_ArithmeticOrLogicalExpression_]: expressions/operator-expr.md#arithmetic-and-logical-binary-operators | |
326 | [_ArrayExpression_]: expressions/array-expr.md | |
e1599b0c XL |
327 | [_AsyncBlockExpression_]: expressions/block-expr.md#async-blocks |
328 | [_AwaitExpression_]: expressions/await-expr.md | |
416331ca XL |
329 | [_AssignmentExpression_]: expressions/operator-expr.md#assignment-expressions |
330 | [_BlockExpression_]: expressions/block-expr.md | |
331 | [_BreakExpression_]: expressions/loop-expr.md#break-expressions | |
332 | [_CallExpression_]: expressions/call-expr.md | |
333 | [_ClosureExpression_]: expressions/closure-expr.md | |
334 | [_ComparisonExpression_]: expressions/operator-expr.md#comparison-operators | |
335 | [_CompoundAssignmentExpression_]: expressions/operator-expr.md#compound-assignment-expressions | |
336 | [_ContinueExpression_]: expressions/loop-expr.md#continue-expressions | |
337 | [_EnumerationVariantExpression_]: expressions/enum-variant-expr.md | |
338 | [_FieldExpression_]: expressions/field-expr.md | |
339 | [_GroupedExpression_]: expressions/grouped-expr.md | |
340 | [_IfExpression_]: expressions/if-expr.md#if-expressions | |
341 | [_IfLetExpression_]: expressions/if-expr.md#if-let-expressions | |
342 | [_IndexExpression_]: expressions/array-expr.md#array-and-slice-indexing-expressions | |
343 | [_LazyBooleanExpression_]: expressions/operator-expr.md#lazy-boolean-operators | |
344 | [_LiteralExpression_]: expressions/literal-expr.md | |
345 | [_LoopExpression_]: expressions/loop-expr.md | |
346 | [_MacroInvocation_]: macros.md#macro-invocation | |
347 | [_MatchExpression_]: expressions/match-expr.md | |
348 | [_MethodCallExpression_]: expressions/method-call-expr.md | |
349 | [_OperatorExpression_]: expressions/operator-expr.md | |
350 | [_OuterAttribute_]: attributes.md | |
351 | [_PathExpression_]: expressions/path-expr.md | |
352 | [_RangeExpression_]: expressions/range-expr.md | |
353 | [_ReturnExpression_]: expressions/return-expr.md | |
354 | [_StructExpression_]: expressions/struct-expr.md | |
355 | [_TupleExpression_]: expressions/tuple-expr.md | |
356 | [_TupleIndexingExpression_]: expressions/tuple-expr.md#tuple-indexing-expressions | |
357 | [_TypeCastExpression_]: expressions/operator-expr.md#type-cast-expressions | |
358 | [_UnsafeBlockExpression_]: expressions/block-expr.md#unsafe-blocks |