]> git.lizzy.rs Git - rust.git/blob - src/doc/trpl/if.md
Rollup merge of #21357 - kimroen:patch-1, r=sanxiyn
[rust.git] / src / doc / trpl / if.md
1 % `if`
2
3 Rust's take on `if` is not particularly complex, but it's much more like the
4 `if` you'll find in a dynamically typed language than in a more traditional
5 systems language. So let's talk about it, to make sure you grasp the nuances.
6
7 `if` is a specific form of a more general concept, the *branch*. The name comes
8 from a branch in a tree: a decision point, where depending on a choice,
9 multiple paths can be taken.
10
11 In the case of `if`, there is one choice that leads down two paths:
12
13 ```rust
14 let x = 5;
15
16 if x == 5 {
17     println!("x is five!");
18 }
19 ```
20
21 If we changed the value of `x` to something else, this line would not print.
22 More specifically, if the expression after the `if` evaluates to `true`, then
23 the block is executed. If it's `false`, then it is not.
24
25 If you want something to happen in the `false` case, use an `else`:
26
27 ```{rust}
28 let x = 5;
29
30 if x == 5 {
31     println!("x is five!");
32 } else {
33     println!("x is not five :(");
34 }
35 ```
36
37 This is all pretty standard. However, you can also do this:
38
39
40 ```{rust}
41 let x = 5;
42
43 let y = if x == 5 {
44     10
45 } else {
46     15
47 }; // y: i32
48 ```
49
50 Which we can (and probably should) write like this:
51
52 ```{rust}
53 let x = 5;
54
55 let y = if x == 5 { 10 } else { 15 }; // y: i32
56 ```
57
58 This reveals two interesting things about Rust: it is an expression-based
59 language, and semicolons are different from semicolons in other 'curly brace
60 and semicolon'-based languages. These two things are related.
61
62 ## Expressions vs. Statements
63
64 Rust is primarily an expression based language. There are only two kinds of
65 statements, and everything else is an expression.
66
67 So what's the difference? Expressions return a value, and statements do not.
68 In many languages, `if` is a statement, and therefore, `let x = if ...` would
69 make no sense. But in Rust, `if` is an expression, which means that it returns
70 a value. We can then use this value to initialize the binding.
71
72 Speaking of which, bindings are a kind of the first of Rust's two statements.
73 The proper name is a *declaration statement*. So far, `let` is the only kind
74 of declaration statement we've seen. Let's talk about that some more.
75
76 In some languages, variable bindings can be written as expressions, not just
77 statements. Like Ruby:
78
79 ```{ruby}
80 x = y = 5
81 ```
82
83 In Rust, however, using `let` to introduce a binding is _not_ an expression. The
84 following will produce a compile-time error:
85
86 ```{ignore}
87 let x = (let y = 5); // expected identifier, found keyword `let`
88 ```
89
90 The compiler is telling us here that it was expecting to see the beginning of
91 an expression, and a `let` can only begin a statement, not an expression.
92
93 Note that assigning to an already-bound variable (e.g. `y = 5`) is still an
94 expression, although its value is not particularly useful. Unlike C, where an
95 assignment evaluates to the assigned value (e.g. `5` in the previous example),
96 in Rust the value of an assignment is the unit type `()` (which we'll cover later).
97
98 The second kind of statement in Rust is the *expression statement*. Its
99 purpose is to turn any expression into a statement. In practical terms, Rust's
100 grammar expects statements to follow other statements. This means that you use
101 semicolons to separate expressions from each other. This means that Rust
102 looks a lot like most other languages that require you to use semicolons
103 at the end of every line, and you will see semicolons at the end of almost
104 every line of Rust code you see.
105
106 What is this exception that makes us say "almost"? You saw it already, in this
107 code:
108
109 ```{rust}
110 let x = 5;
111
112 let y: i32 = if x == 5 { 10 } else { 15 };
113 ```
114
115 Note that I've added the type annotation to `y`, to specify explicitly that I
116 want `y` to be an integer.
117
118 This is not the same as this, which won't compile:
119
120 ```{ignore}
121 let x = 5;
122
123 let y: i32 = if x == 5 { 10; } else { 15; };
124 ```
125
126 Note the semicolons after the 10 and 15. Rust will give us the following error:
127
128 ```text
129 error: mismatched types: expected `i32`, found `()` (expected i32, found ())
130 ```
131
132 We expected an integer, but we got `()`. `()` is pronounced *unit*, and is a
133 special type in Rust's type system. In Rust, `()` is _not_ a valid value for a
134 variable of type `i32`. It's only a valid value for variables of the type `()`,
135 which aren't very useful. Remember how we said statements don't return a value?
136 Well, that's the purpose of unit in this case. The semicolon turns any
137 expression into a statement by throwing away its value and returning unit
138 instead.
139
140 There's one more time in which you won't see a semicolon at the end of a line
141 of Rust code. For that, we'll need our next concept: functions.