Statements - The Rust Reference

## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

[statement]

# Statements

[statement.syntax]

Syntax
Statement →
;
| Item
| LetStatement
| ExpressionStatement
| OuterAttribute* MacroInvocationSemi

[statement.intro]

A statement is a component of a block, which is in turn a component of an outer expression or function.

[statement.kind]

Rust has two kinds of statement: declaration statements and expression statements.

[statement.decl]

## Declaration statements

A declaration statement is one that introduces one or more names into the enclosing statement block. The declared names may denote new variables or new items.

The two kinds of declaration statements are item declarations and `let` statements.

[statement.item]

### Item declarations

[statement.item.intro]

An item declaration statement has a syntactic form identical to an item declaration within a module.

[statement.item.scope]

Declaring an item within a statement block restricts its scope to the block containing the statement. The item is not given a canonical path nor are any sub-items it may declare.

[statement.item.associated-scope]

The exception to this is that associated items defined by implementations are still accessible in outer scopes as long as the item and, if applicable, trait are accessible. It is otherwise identical in meaning to declaring the item inside a module.

[statement.item.outer-generics]

There is no implicit capture of the containing function’s generic parameters, parameters, and local variables. For example, `inner` may not access `outer_var`.

    #![allow(unused)]
    fn main() {
    fn outer() {
      let outer_var = true;

      fn inner() { /* outer_var is not in scope here */ }

      inner();
    }
    }

[statement.let]

### `let` statements

[statement.let.syntax]

Syntax
LetStatement →
OuterAttribute* let PatternNoTopAlt ( : Type )?
(
= Expression
| = Expressionexcept LazyBooleanExpression or end with a `}` else BlockExpression
)? ;

[statement.let.intro]

A `let` statement introduces a new set of variables, given by a pattern. The pattern is followed optionally by a type annotation and then either ends, or is followed by an initializer expression plus an optional `else` block.

[statement.let.inference]

When no type annotation is given, the compiler will infer the type, or signal an error if insufficient type information is available for definite inference.

[statement.let.scope]

Any variables introduced by a variable declaration are visible from the point of declaration until the end of the enclosing block scope, except when they are shadowed by another variable declaration.

[statement.let.constraint]

If an `else` block is not present, the pattern must be irrefutable. If an `else` block is present, the pattern may be refutable.

[statement.let.behavior]

If the pattern does not match (this requires it to be refutable), the `else` block is executed. The `else` block must always diverge (evaluate to the never type).

    #![allow(unused)]
    fn main() {
    let (mut v, w) = (vec![1, 2, 3], 42); // The bindings may be mut or const
    let Some(t) = v.pop() else { // Refutable patterns require an else block
        panic!(); // The else block must diverge
    };
    let [u, v] = [v[0], v[1]] else { // This pattern is irrefutable, so the compiler
                                     // will lint as the else block is redundant.
        panic!();
    };
    }

[statement.expr]

## Expression statements

[statement.expr.syntax]

Syntax
ExpressionStatement →
ExpressionWithoutBlock ;
| ExpressionWithBlock ;?

[statement.expr.intro]

An expression statement is one that evaluates an expression and ignores its result. As a rule, an expression statement’s purpose is to trigger the effects of evaluating its expression.

[statement.expr.restriction-semicolon]

An expression that consists of only a block expression or control flow expression, if used in a context where a statement is permitted, can omit the trailing semicolon. This can cause an ambiguity between it being parsed as a standalone statement and as a part of another expression; in this case, it is parsed as a statement.

[statement.expr.constraint-block]

The type of ExpressionWithBlock expressions when used as statements must be the unit type.

    #![allow(unused)]
    fn main() {
    let mut v = vec![1, 2, 3];
    v.pop();          // Ignore the element returned from pop
    if v.is_empty() {
        v.push(5);
    } else {
        v.remove(0);
    }                 // Semicolon can be omitted.
    [1];              // Separate expression statement, not an indexing expression.
    }

When the trailing semicolon is omitted, the result must be type `()`.

    #![allow(unused)]
    fn main() {
    // bad: the block's type is i32, not ()
    // Error: expected `()` because of default return type
    // if true {
    //   1
    // }

    // good: the block's type is i32
    if true {
      1
    } else {
      2
    };
    }

[statement.attribute]

## Attributes on statements

Statements accept outer attributes. The attributes that have meaning on a statement are `cfg`, and the lint check attributes.