]>
Commit | Line | Data |
---|---|---|
ea8adc8c XL |
1 | # Block expressions |
2 | ||
8faf50e0 XL |
3 | > **<sup>Syntax</sup>**\ |
4 | > _BlockExpression_ :\ | |
5 | > `{`\ | |
6 | > [_InnerAttribute_]<sup>\*</sup>\ | |
13cf67c4 | 7 | > _Statements_<sup>?</sup>\ |
8faf50e0 | 8 | > `}` |
b7449926 XL |
9 | > |
10 | > _Statements_ :\ | |
13cf67c4 XL |
11 | > [_Statement_]<sup>\+</sup>\ |
12 | > | [_Statement_]<sup>\+</sup> [_ExpressionWithoutBlock_]\ | |
13 | > | [_ExpressionWithoutBlock_] | |
14 | ||
6a06907d XL |
15 | A *block expression*, or *block*, is a control flow expression and anonymous namespace scope for items and variable declarations. |
16 | As a control flow expression, a block sequentially executes its component non-item declaration statements and then its final optional expression. | |
17 | As an anonymous namespace scope, item declarations are only in scope inside the block itself and variables declared by `let` statements are in scope from the next statement until the end of the block. | |
18 | ||
cdc7bbd5 XL |
19 | The syntax for a block is `{`, then any [inner attributes], then any number of [statements], then an optional expression, called the final operand, and finally a `}`. |
20 | ||
21 | Statements are usually required to be followed by a semicolon, with two exceptions: | |
22 | ||
23 | 1. Item declaration statements do not need to be followed by a semicolon. | |
24 | 2. Expression statements usually require a following semicolon except if its outer expression is a flow control expression. | |
25 | ||
6a06907d XL |
26 | Furthermore, extra semicolons between statements are allowed, but these semicolons do not affect semantics. |
27 | ||
28 | When evaluating a block expression, each statement, except for item declaration statements, is executed sequentially. | |
cdc7bbd5 | 29 | Then the final operand is executed, if given. |
6a06907d | 30 | |
cdc7bbd5 | 31 | The type of a block is the type of the final operand, or `()` if the final operand is omitted. |
abe05a73 | 32 | |
b7449926 XL |
33 | ```rust |
34 | # fn fn_call() {} | |
35 | let _: () = { | |
36 | fn_call(); | |
37 | }; | |
ea8adc8c | 38 | |
b7449926 XL |
39 | let five: i32 = { |
40 | fn_call(); | |
41 | 5 | |
42 | }; | |
ea8adc8c | 43 | |
b7449926 | 44 | assert_eq!(5, five); |
ea8adc8c XL |
45 | ``` |
46 | ||
6a06907d | 47 | > Note: As a control flow expression, if a block expression is the outer expression of an expression statement, the expected type is `()` unless it is followed immediately by a semicolon. |
ea8adc8c | 48 | |
cdc7bbd5 | 49 | Blocks are always [value expressions] and evaluate the last operand in value expression context. |
b7449926 | 50 | |
cdc7bbd5 XL |
51 | > **Note**: This can be used to force moving a value if really needed. |
52 | > For example, the following example fails on the call to `consume_self` because the struct was moved out of `s` in the block expression. | |
53 | > | |
54 | > ```rust,compile_fail | |
55 | > struct Struct; | |
56 | > | |
57 | > impl Struct { | |
58 | > fn consume_self(self) {} | |
59 | > fn borrow_self(&self) {} | |
60 | > } | |
61 | > | |
62 | > fn move_by_block_expression() { | |
63 | > let s = Struct; | |
64 | > | |
65 | > // Move the value out of `s` in the block expression. | |
66 | > (&{ s }).borrow_self(); | |
67 | > | |
68 | > // Fails to execute because `s` is moved out of. | |
69 | > s.consume_self(); | |
70 | > } | |
71 | > ``` | |
ea8adc8c | 72 | |
e1599b0c XL |
73 | ## `async` blocks |
74 | ||
75 | > **<sup>Syntax</sup>**\ | |
76 | > _AsyncBlockExpression_ :\ | |
77 | > `async` `move`<sup>?</sup> _BlockExpression_ | |
78 | ||
cdc7bbd5 | 79 | An *async block* is a variant of a block expression which evaluates to a future. |
6a06907d | 80 | The final expression of the block, if present, determines the result value of the future. |
e1599b0c XL |
81 | |
82 | Executing an async block is similar to executing a closure expression: | |
83 | its immediate effect is to produce and return an anonymous type. | |
6a06907d XL |
84 | Whereas closures return a type that implements one or more of the [`std::ops::Fn`] traits, however, the type returned for an async block implements the [`std::future::Future`] trait. |
85 | The actual data format for this type is unspecified. | |
e1599b0c | 86 | |
6a06907d | 87 | > **Note:** The future type that rustc generates is roughly equivalent to an enum with one variant per `await` point, where each variant stores the data needed to resume from its corresponding point. |
e1599b0c XL |
88 | |
89 | > **Edition differences**: Async blocks are only available beginning with Rust 2018. | |
90 | ||
e1599b0c XL |
91 | ### Capture modes |
92 | ||
6a06907d XL |
93 | Async blocks capture variables from their environment using the same [capture modes] as closures. |
94 | Like closures, when written `async { .. }` the capture mode for each variable will be inferred from the content of the block. | |
95 | `async move { .. }` blocks however will move all referenced variables into the resulting future. | |
e1599b0c | 96 | |
e1599b0c XL |
97 | ### Async context |
98 | ||
6a06907d XL |
99 | Because async blocks construct a future, they define an **async context** which can in turn contain [`await` expressions]. |
100 | Async contexts are established by async blocks as well as the bodies of async functions, whose semantics are defined in terms of async blocks. | |
e1599b0c | 101 | |
e1599b0c XL |
102 | ### Control-flow operators |
103 | ||
6a06907d XL |
104 | Async blocks act like a function boundary, much like closures. |
105 | Therefore, the `?` operator and `return` expressions both affect the output of the future, not the enclosing function or other context. | |
106 | That is, `return <expr>` from within a closure will return the result of `<expr>` as the output of the future. | |
107 | Similarly, if `<expr>?` propagates an error, that error is propagated as the result of the future. | |
e1599b0c | 108 | |
6a06907d XL |
109 | Finally, the `break` and `continue` keywords cannot be used to branch out from an async block. |
110 | Therefore the following is illegal: | |
e1599b0c | 111 | |
136023e0 | 112 | ```rust,compile_fail |
e1599b0c XL |
113 | loop { |
114 | async move { | |
115 | break; // This would break out of the loop. | |
116 | } | |
117 | } | |
118 | ``` | |
119 | ||
ea8adc8c XL |
120 | ## `unsafe` blocks |
121 | ||
8faf50e0 XL |
122 | > **<sup>Syntax</sup>**\ |
123 | > _UnsafeBlockExpression_ :\ | |
abe05a73 XL |
124 | > `unsafe` _BlockExpression_ |
125 | ||
416331ca | 126 | _See [`unsafe` block](../unsafe-blocks.md) for more information on when to use `unsafe`_ |
ea8adc8c | 127 | |
6a06907d XL |
128 | A block of code can be prefixed with the `unsafe` keyword to permit [unsafe operations]. |
129 | Examples: | |
abe05a73 XL |
130 | |
131 | ```rust | |
132 | unsafe { | |
133 | let b = [13u8, 17u8]; | |
134 | let a = &b[0] as *const u8; | |
135 | assert_eq!(*a, 13); | |
136 | assert_eq!(*a.offset(1), 17); | |
137 | } | |
138 | ||
b7449926 XL |
139 | # unsafe fn an_unsafe_fn() -> i32 { 10 } |
140 | let a = unsafe { an_unsafe_fn() }; | |
abe05a73 XL |
141 | ``` |
142 | ||
8faf50e0 XL |
143 | ## Attributes on block expressions |
144 | ||
6a06907d | 145 | [Inner attributes] are allowed directly after the opening brace of a block expression in the following situations: |
13cf67c4 XL |
146 | |
147 | * [Function] and [method] bodies. | |
148 | * Loop bodies ([`loop`], [`while`], [`while let`], and [`for`]). | |
149 | * Block expressions used as a [statement]. | |
150 | * Block expressions as elements of [array expressions], [tuple expressions], | |
6a06907d | 151 | [call expressions], and tuple-style [struct] expressions. |
13cf67c4 XL |
152 | * A block expression as the tail expression of another block expression. |
153 | <!-- Keep list in sync with expressions.md --> | |
154 | ||
6a06907d | 155 | The attributes that have meaning on a block expression are [`cfg`] and [the lint check attributes]. |
8faf50e0 | 156 | |
6a06907d | 157 | For example, this function returns `true` on unix platforms and `false` on other platforms. |
8faf50e0 XL |
158 | |
159 | ```rust | |
160 | fn is_unix_platform() -> bool { | |
161 | #[cfg(unix)] { true } | |
162 | #[cfg(not(unix))] { false } | |
163 | } | |
164 | ``` | |
165 | ||
416331ca XL |
166 | [_ExpressionWithoutBlock_]: ../expressions.md |
167 | [_InnerAttribute_]: ../attributes.md | |
168 | [_Statement_]: ../statements.md | |
cdc7bbd5 | 169 | [`await` expressions]: await-expr.md |
416331ca XL |
170 | [`cfg`]: ../conditional-compilation.md |
171 | [`for`]: loop-expr.md#iterator-loops | |
172 | [`loop`]: loop-expr.md#infinite-loops | |
cdc7bbd5 XL |
173 | [`std::ops::Fn`]: ../../std/ops/trait.Fn.html |
174 | [`std::future::Future`]: ../../std/future/trait.Future.html | |
416331ca XL |
175 | [`while let`]: loop-expr.md#predicate-pattern-loops |
176 | [`while`]: loop-expr.md#predicate-loops | |
177 | [array expressions]: array-expr.md | |
178 | [call expressions]: call-expr.md | |
cdc7bbd5 | 179 | [capture modes]: ../types/closure.md#capture-modes |
416331ca XL |
180 | [function]: ../items/functions.md |
181 | [inner attributes]: ../attributes.md | |
182 | [method]: ../items/associated-items.md#methods | |
cdc7bbd5 XL |
183 | [mutable reference]: ../types/pointer.md#mutables-references- |
184 | [shared references]: ../types/pointer.md#shared-references- | |
416331ca XL |
185 | [statement]: ../statements.md |
186 | [statements]: ../statements.md | |
187 | [struct]: struct-expr.md | |
188 | [the lint check attributes]: ../attributes/diagnostics.md#lint-check-attributes | |
189 | [tuple expressions]: tuple-expr.md | |
190 | [unsafe operations]: ../unsafety.md | |
191 | [value expressions]: ../expressions.md#place-expressions-and-value-expressions |