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