]>
Commit | Line | Data |
---|---|---|
ea8adc8c XL |
1 | # `if` and `if let` expressions |
2 | ||
3 | ## `if` expressions | |
4 | ||
8faf50e0 XL |
5 | > **<sup>Syntax</sup>**\ |
6 | > _IfExpression_ :\ | |
7 | > `if` [_Expression_]<sub>_except struct expression_</sub> [_BlockExpression_]\ | |
ff7c6d11 XL |
8 | > (`else` ( |
9 | > [_BlockExpression_] | |
10 | > | _IfExpression_ | |
8faf50e0 | 11 | > | _IfLetExpression_ ) )<sup>\?</sup> |
ff7c6d11 | 12 | |
6a06907d XL |
13 | An `if` expression is a conditional branch in program control. |
14 | The syntax of an `if` expression is a condition operand, followed by a consequent block, any number of `else if` conditions and blocks, and an optional trailing `else` block. | |
15 | The condition operands must have the [boolean type]. | |
16 | If a condition operand evaluates to `true`, the consequent block is executed and any subsequent `else if` or `else` block is skipped. | |
17 | If a condition operand evaluates to `false`, the consequent block is skipped and any subsequent `else if` condition is evaluated. | |
18 | If all `if` and `else if` conditions evaluate to `false` then any `else` block is executed. | |
19 | An if expression evaluates to the same value as the executed block, or `()` if no block is evaluated. | |
20 | An `if` expression must have the same type in all situations. | |
ea8adc8c XL |
21 | |
22 | ```rust | |
23 | # let x = 3; | |
24 | if x == 4 { | |
25 | println!("x is four"); | |
26 | } else if x == 3 { | |
27 | println!("x is three"); | |
28 | } else { | |
29 | println!("x is something else"); | |
30 | } | |
31 | ||
32 | let y = if 12 * 15 > 150 { | |
33 | "Bigger" | |
34 | } else { | |
35 | "Smaller" | |
36 | }; | |
37 | assert_eq!(y, "Bigger"); | |
38 | ``` | |
ff7c6d11 | 39 | |
ea8adc8c XL |
40 | ## `if let` expressions |
41 | ||
8faf50e0 XL |
42 | > **<sup>Syntax</sup>**\ |
43 | > _IfLetExpression_ :\ | |
532ac7d7 | 44 | > `if` `let` [_MatchArmPatterns_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub> |
8faf50e0 | 45 | > [_BlockExpression_]\ |
ff7c6d11 XL |
46 | > (`else` ( |
47 | > [_BlockExpression_] | |
48 | > | _IfExpression_ | |
8faf50e0 | 49 | > | _IfLetExpression_ ) )<sup>\?</sup> |
ff7c6d11 | 50 | |
6a06907d XL |
51 | An `if let` expression is semantically similar to an `if` expression but in place of a condition operand it expects the keyword `let` followed by a pattern, an `=` and a [scrutinee] operand. |
52 | If the value of the scrutinee matches the pattern, the corresponding block will execute. | |
53 | Otherwise, flow proceeds to the following `else` block if it exists. | |
54 | Like `if` expressions, `if let` expressions have a value determined by the block that is evaluated. | |
ea8adc8c XL |
55 | |
56 | ```rust | |
57 | let dish = ("Ham", "Eggs"); | |
58 | ||
59 | // this body will be skipped because the pattern is refuted | |
60 | if let ("Bacon", b) = dish { | |
61 | println!("Bacon is served with {}", b); | |
62 | } else { | |
63 | // This block is evaluated instead. | |
64 | println!("No bacon will be served"); | |
65 | } | |
66 | ||
67 | // this body will execute | |
68 | if let ("Ham", b) = dish { | |
69 | println!("Ham is served with {}", b); | |
70 | } | |
532ac7d7 XL |
71 | |
72 | if let _ = 5 { | |
73 | println!("Irrefutable patterns are always true"); | |
74 | } | |
ea8adc8c | 75 | ``` |
ff7c6d11 XL |
76 | |
77 | `if` and `if let` expressions can be intermixed: | |
78 | ||
79 | ```rust | |
80 | let x = Some(3); | |
81 | let a = if let Some(1) = x { | |
82 | 1 | |
83 | } else if x == Some(2) { | |
84 | 2 | |
85 | } else if let Some(y) = x { | |
86 | y | |
87 | } else { | |
88 | -1 | |
89 | }; | |
90 | assert_eq!(a, 3); | |
91 | ``` | |
92 | ||
532ac7d7 | 93 | An `if let` expression is equivalent to a [`match` expression] as follows: |
0bf4aa26 | 94 | |
60c5eb7d | 95 | <!-- ignore: expansion example --> |
0bf4aa26 | 96 | ```rust,ignore |
532ac7d7 | 97 | if let PATS = EXPR { |
0bf4aa26 XL |
98 | /* body */ |
99 | } else { | |
100 | /*else */ | |
101 | } | |
102 | ``` | |
103 | ||
104 | is equivalent to | |
105 | ||
60c5eb7d | 106 | <!-- ignore: expansion example --> |
0bf4aa26 XL |
107 | ```rust,ignore |
108 | match EXPR { | |
532ac7d7 | 109 | PATS => { /* body */ }, |
0bf4aa26 XL |
110 | _ => { /* else */ }, // () if there is no else |
111 | } | |
112 | ``` | |
113 | ||
6a06907d | 114 | Multiple patterns may be specified with the `|` operator. This has the same semantics as with `|` in `match` expressions: |
532ac7d7 XL |
115 | |
116 | ```rust | |
117 | enum E { | |
118 | X(u8), | |
119 | Y(u8), | |
120 | Z(u8), | |
121 | } | |
122 | let v = E::Y(12); | |
123 | if let E::X(n) | E::Y(n) = v { | |
124 | assert_eq!(n, 12); | |
125 | } | |
126 | ``` | |
127 | ||
0bf4aa26 | 128 | The expression cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_]. |
6a06907d XL |
129 | Use of a lazy boolean operator is ambiguous with a planned feature change of the language (the implementation of if-let chains - see [eRFC 2947][_eRFCIfLetChain_]). |
130 | When lazy boolean operator expression is desired, this can be achieved by using parenthesis as below: | |
0bf4aa26 | 131 | |
60c5eb7d | 132 | <!-- ignore: psuedo code --> |
0bf4aa26 XL |
133 | ```rust,ignore |
134 | // Before... | |
135 | if let PAT = EXPR && EXPR { .. } | |
136 | ||
137 | // After... | |
138 | if let PAT = ( EXPR && EXPR ) { .. } | |
139 | ||
140 | // Before... | |
141 | if let PAT = EXPR || EXPR { .. } | |
142 | ||
143 | // After... | |
144 | if let PAT = ( EXPR || EXPR ) { .. } | |
145 | ``` | |
146 | ||
416331ca XL |
147 | [_BlockExpression_]: block-expr.md |
148 | [_Expression_]: ../expressions.md | |
149 | [_LazyBooleanOperatorExpression_]: operator-expr.md#lazy-boolean-operators | |
150 | [_MatchArmPatterns_]: match-expr.md | |
0bf4aa26 | 151 | [_eRFCIfLetChain_]: https://github.com/rust-lang/rfcs/blob/master/text/2497-if-let-chains.md#rollout-plan-and-transitioning-to-rust-2018 |
416331ca | 152 | [`match` expression]: match-expr.md |
6a06907d | 153 | [boolean type]: ../types/boolean.md |
416331ca | 154 | [scrutinee]: ../glossary.md#scrutinee |