| # Block expressions |
| |
| > **<sup>Syntax</sup>**\ |
| > _BlockExpression_ :\ |
| > `{`\ |
| > [_InnerAttribute_]<sup>\*</sup>\ |
| > _Statements_<sup>?</sup>\ |
| > `}` |
| > |
| > _Statements_ :\ |
| > [_Statement_]<sup>\+</sup>\ |
| > | [_Statement_]<sup>\+</sup> [_ExpressionWithoutBlock_]\ |
| > | [_ExpressionWithoutBlock_] |
| |
| A *block expression*, or *block*, is a control flow expression and anonymous namespace scope for items and variable declarations. |
| As a control flow expression, a block sequentially executes its component non-item declaration statements and then its final optional expression. |
| 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. |
| See the [scopes] chapter for more details. |
| |
| 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 `}`. |
| |
| Statements are usually required to be followed by a semicolon, with two exceptions: |
| |
| 1. Item declaration statements do not need to be followed by a semicolon. |
| 2. Expression statements usually require a following semicolon except if its outer expression is a flow control expression. |
| |
| Furthermore, extra semicolons between statements are allowed, but these semicolons do not affect semantics. |
| |
| When evaluating a block expression, each statement, except for item declaration statements, is executed sequentially. |
| Then the final operand is executed, if given. |
| |
| The type of a block is the type of the final operand, or `()` if the final operand is omitted. |
| |
| ```rust |
| # fn fn_call() {} |
| let _: () = { |
| fn_call(); |
| }; |
| |
| let five: i32 = { |
| fn_call(); |
| 5 |
| }; |
| |
| assert_eq!(5, five); |
| ``` |
| |
| > 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. |
| |
| Blocks are always [value expressions] and evaluate the last operand in value expression context. |
| |
| > **Note**: This can be used to force moving a value if really needed. |
| > For example, the following example fails on the call to `consume_self` because the struct was moved out of `s` in the block expression. |
| > |
| > ```rust,compile_fail |
| > struct Struct; |
| > |
| > impl Struct { |
| > fn consume_self(self) {} |
| > fn borrow_self(&self) {} |
| > } |
| > |
| > fn move_by_block_expression() { |
| > let s = Struct; |
| > |
| > // Move the value out of `s` in the block expression. |
| > (&{ s }).borrow_self(); |
| > |
| > // Fails to execute because `s` is moved out of. |
| > s.consume_self(); |
| > } |
| > ``` |
| |
| ## `async` blocks |
| |
| > **<sup>Syntax</sup>**\ |
| > _AsyncBlockExpression_ :\ |
| > `async` `move`<sup>?</sup> _BlockExpression_ |
| |
| An *async block* is a variant of a block expression which evaluates to a future. |
| The final expression of the block, if present, determines the result value of the future. |
| |
| Executing an async block is similar to executing a closure expression: |
| its immediate effect is to produce and return an anonymous type. |
| 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. |
| The actual data format for this type is unspecified. |
| |
| > **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. |
| |
| > **Edition differences**: Async blocks are only available beginning with Rust 2018. |
| |
| ### Capture modes |
| |
| Async blocks capture variables from their environment using the same [capture modes] as closures. |
| Like closures, when written `async { .. }` the capture mode for each variable will be inferred from the content of the block. |
| `async move { .. }` blocks however will move all referenced variables into the resulting future. |
| |
| ### Async context |
| |
| Because async blocks construct a future, they define an **async context** which can in turn contain [`await` expressions]. |
| Async contexts are established by async blocks as well as the bodies of async functions, whose semantics are defined in terms of async blocks. |
| |
| ### Control-flow operators |
| |
| Async blocks act like a function boundary, much like closures. |
| Therefore, the `?` operator and `return` expressions both affect the output of the future, not the enclosing function or other context. |
| That is, `return <expr>` from within an async block will return the result of `<expr>` as the output of the future. |
| Similarly, if `<expr>?` propagates an error, that error is propagated as the result of the future. |
| |
| Finally, the `break` and `continue` keywords cannot be used to branch out from an async block. |
| Therefore the following is illegal: |
| |
| ```rust,compile_fail |
| loop { |
| async move { |
| break; // error[E0267]: `break` inside of an `async` block |
| } |
| } |
| ``` |
| |
| ## `const` blocks |
| |
| > **<sup>Syntax</sup>**\ |
| > _ConstBlockExpression_ :\ |
| > `const` _BlockExpression_ |
| |
| A *const block* is a variant of a block expression whose body evaluates at compile-time instead of at runtime. |
| |
| Const blocks allows you to define a constant value without having to define new [constant items], and thus they are also sometimes referred as *inline consts*. |
| It also supports type inference so there is no need to specify the type, unlike [constant items]. |
| |
| Const blocks have the ability to reference generic parameters in scope, unlike [free][free item] constant items. |
| They are desugared to constant items with generic parameters in scope (similar to associated constants, but without a trait or type they are associated with). |
| For example, this code: |
| |
| ```rust |
| fn foo<T>() -> usize { |
| const { std::mem::size_of::<T>() + 1 } |
| } |
| ``` |
| |
| is equivalent to: |
| |
| ```rust |
| fn foo<T>() -> usize { |
| { |
| struct Const<T>(T); |
| impl<T> Const<T> { |
| const CONST: usize = std::mem::size_of::<T>() + 1; |
| } |
| Const::<T>::CONST |
| } |
| } |
| ``` |
| |
| If the const block expression is executed at runtime, then the constant is guaranteed to be evaluated, even if its return value is ignored: |
| |
| ```rust |
| fn foo<T>() -> usize { |
| // If this code ever gets executed, then the assertion has definitely |
| // been evaluated at compile-time. |
| const { assert!(std::mem::size_of::<T>() > 0); } |
| // Here we can have unsafe code relying on the type being non-zero-sized. |
| /* ... */ |
| 42 |
| } |
| ``` |
| |
| If the const block expression is not executed at runtime, it may or may not be evaluated: |
| ```rust,compile_fail |
| if false { |
| // The panic may or may not occur when the program is built. |
| const { panic!(); } |
| } |
| ``` |
| |
| ## `unsafe` blocks |
| |
| > **<sup>Syntax</sup>**\ |
| > _UnsafeBlockExpression_ :\ |
| > `unsafe` _BlockExpression_ |
| |
| _See [`unsafe` blocks] for more information on when to use `unsafe`_. |
| |
| A block of code can be prefixed with the `unsafe` keyword to permit [unsafe operations]. |
| Examples: |
| |
| ```rust |
| unsafe { |
| let b = [13u8, 17u8]; |
| let a = &b[0] as *const u8; |
| assert_eq!(*a, 13); |
| assert_eq!(*a.offset(1), 17); |
| } |
| |
| # unsafe fn an_unsafe_fn() -> i32 { 10 } |
| let a = unsafe { an_unsafe_fn() }; |
| ``` |
| |
| ## Labelled block expressions |
| |
| Labelled block expressions are documented in the [Loops and other breakable expressions] section. |
| |
| ## Attributes on block expressions |
| |
| [Inner attributes] are allowed directly after the opening brace of a block expression in the following situations: |
| |
| * [Function] and [method] bodies. |
| * Loop bodies ([`loop`], [`while`], [`while let`], and [`for`]). |
| * Block expressions used as a [statement]. |
| * Block expressions as elements of [array expressions], [tuple expressions], |
| [call expressions], and tuple-style [struct] expressions. |
| * A block expression as the tail expression of another block expression. |
| <!-- Keep list in sync with expressions.md --> |
| |
| The attributes that have meaning on a block expression are [`cfg`] and [the lint check attributes]. |
| |
| For example, this function returns `true` on unix platforms and `false` on other platforms. |
| |
| ```rust |
| fn is_unix_platform() -> bool { |
| #[cfg(unix)] { true } |
| #[cfg(not(unix))] { false } |
| } |
| ``` |
| |
| [_ExpressionWithoutBlock_]: ../expressions.md |
| [_InnerAttribute_]: ../attributes.md |
| [_Statement_]: ../statements.md |
| [`await` expressions]: await-expr.md |
| [`cfg`]: ../conditional-compilation.md |
| [`for`]: loop-expr.md#iterator-loops |
| [`loop`]: loop-expr.md#infinite-loops |
| [`std::ops::Fn`]: ../../std/ops/trait.Fn.html |
| [`std::future::Future`]: ../../std/future/trait.Future.html |
| [`unsafe` blocks]: ../unsafe-keyword.md#unsafe-blocks-unsafe- |
| [`while let`]: loop-expr.md#predicate-pattern-loops |
| [`while`]: loop-expr.md#predicate-loops |
| [array expressions]: array-expr.md |
| [call expressions]: call-expr.md |
| [capture modes]: ../types/closure.md#capture-modes |
| [constant items]: ../items/constant-items.md |
| [free item]: ../glossary.md#free-item |
| [function]: ../items/functions.md |
| [inner attributes]: ../attributes.md |
| [method]: ../items/associated-items.md#methods |
| [mutable reference]: ../types/pointer.md#mutables-references- |
| [scopes]: ../names/scopes.md |
| [shared references]: ../types/pointer.md#shared-references- |
| [statement]: ../statements.md |
| [statements]: ../statements.md |
| [struct]: struct-expr.md |
| [the lint check attributes]: ../attributes/diagnostics.md#lint-check-attributes |
| [tuple expressions]: tuple-expr.md |
| [unsafe operations]: ../unsafety.md |
| [value expressions]: ../expressions.md#place-expressions-and-value-expressions |
| [Loops and other breakable expressions]: loop-expr.md#labelled-block-expressions |