summaryrefslogtreecommitdiffstats
path: root/src/doc/reference/src/statements.md
blob: 8d9c21d7db69f684c4aec79eb60d9f7075bd920d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# Statements

> **<sup>Syntax</sup>**\
> _Statement_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; `;`\
> &nbsp;&nbsp; | [_Item_]\
> &nbsp;&nbsp; | [_LetStatement_]\
> &nbsp;&nbsp; | [_ExpressionStatement_]\
> &nbsp;&nbsp; | [_MacroInvocationSemi_]


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

Rust has two kinds of statement: [declaration
statements](#declaration-statements) and [expression
statements](#expression-statements).

## 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][item].

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

### Item declarations

An *item declaration statement* has a syntactic form identical to an
[item declaration][item] within a [module]. 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. 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.

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

```rust
fn outer() {
  let outer_var = true;

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

  inner();
}
```

### `let` statements

> **<sup>Syntax</sup>**\
> _LetStatement_ :\
> &nbsp;&nbsp; [_OuterAttribute_]<sup>\*</sup> `let` [_PatternNoTopAlt_]
>     ( `:` [_Type_] )<sup>?</sup> (`=` [_Expression_] )<sup>?</sup> `;`

A *`let` statement* introduces a new set of [variables], given by an
irrefutable [pattern]. The pattern is followed optionally by a type
annotation and then optionally by an initializer expression. 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. 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.

## Expression statements

> **<sup>Syntax</sup>**\
> _ExpressionStatement_ :\
> &nbsp;&nbsp; &nbsp;&nbsp; [_ExpressionWithoutBlock_][expression] `;`\
> &nbsp;&nbsp; | [_ExpressionWithBlock_][expression] `;`<sup>?</sup>

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.

An expression that consists of only a [block expression][block] 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. The type of [_ExpressionWithBlock_][expression]
expressions when used as statements must be the unit type.

```rust
# 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 `()`.

```rust
// 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
};
```

## Attributes on Statements

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

[block]: expressions/block-expr.md
[expression]: expressions.md
[function]: items/functions.md
[item]: items.md
[module]: items/modules.md
[canonical path]: paths.md#canonical-paths
[implementations]: items/implementations.md
[variables]: variables.md
[outer attributes]: attributes.md
[`cfg`]: conditional-compilation.md
[the lint check attributes]: attributes/diagnostics.md#lint-check-attributes
[pattern]: patterns.md
[_ExpressionStatement_]: #expression-statements
[_Expression_]: expressions.md
[_Item_]: items.md
[_LetStatement_]: #let-statements
[_MacroInvocationSemi_]: macros.md#macro-invocation
[_OuterAttribute_]: attributes.md
[_PatternNoTopAlt_]: patterns.md
[_Type_]: types.md