Block expressions - The Rust Reference

# Block expressions

> Syntax
> BlockExpression :
> `{`
> InnerAttribute*
> Statements?
> `}`

> Statements :
> Statement+
> | Statement+ 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.

Blocks are written as `{`, then any inner attributes, then statements, then an optional expression, and finally a `}`. Statements are usually required to be followed by a semicolon, with two exceptions. Item declaration statements do not need to be followed by a semicolon. 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.

> Note: The semicolon following a statement is not a part of the statement itself. They are invalid when using the `stmt` macro matcher.

When evaluating a block expression, each statement, except for item declaration statements, is executed sequentially. Then the final expression is executed, if given.

The type of a block is the type of the final expression, or `()` if the final expression is omitted.

    #![allow(unused_variables)]
    fn main() {
    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 expression in value expression context. 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.

    #![allow(unused_variables)]
    fn main() {
    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

> Syntax
> AsyncBlockExpression :
> `async` `move`? 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 a closure 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:

    #![allow(unused_variables)]
    fn main() {
    loop {
        async move {
            break; // This would break out of the loop.
        }
    }
    }

## `unsafe` blocks

> Syntax
> UnsafeBlockExpression :
> `unsafe` BlockExpression

See `unsafe` block for more information on when to use `unsafe`

A block of code can be prefixed with the `unsafe` keyword to permit unsafe operations. Examples:

    #![allow(unused_variables)]
    fn main() {
    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() };
    }

## 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 and enum variant expressions.
- A block expression as the tail expression of another block expression.

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.

    #![allow(unused_variables)]
    fn main() {
    fn is_unix_platform() -> bool {
        #[cfg(unix)] { true }
        #[cfg(not(unix))] { false }
    }
    }