]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | % Patterns |
2 | ||
9346a6ac AL |
3 | Patterns are quite common in Rust. We use them in [variable |
4 | bindings][bindings], [match statements][match], and other places, too. Let’s go | |
5 | on a whirlwind tour of all of the things patterns can do! | |
6 | ||
7 | [bindings]: variable-bindings.html | |
8 | [match]: match.html | |
1a4d82fc JJ |
9 | |
10 | A quick refresher: you can match against literals directly, and `_` acts as an | |
9346a6ac | 11 | ‘any’ case: |
1a4d82fc | 12 | |
9346a6ac | 13 | ```rust |
85aaf69f | 14 | let x = 1; |
1a4d82fc JJ |
15 | |
16 | match x { | |
17 | 1 => println!("one"), | |
18 | 2 => println!("two"), | |
19 | 3 => println!("three"), | |
20 | _ => println!("anything"), | |
21 | } | |
22 | ``` | |
23 | ||
bd371182 AL |
24 | This prints `one`. |
25 | ||
9346a6ac AL |
26 | # Multiple patterns |
27 | ||
1a4d82fc JJ |
28 | You can match multiple patterns with `|`: |
29 | ||
9346a6ac | 30 | ```rust |
85aaf69f | 31 | let x = 1; |
1a4d82fc JJ |
32 | |
33 | match x { | |
34 | 1 | 2 => println!("one or two"), | |
35 | 3 => println!("three"), | |
36 | _ => println!("anything"), | |
37 | } | |
38 | ``` | |
39 | ||
bd371182 AL |
40 | This prints `one or two`. |
41 | ||
9346a6ac AL |
42 | # Ranges |
43 | ||
1a4d82fc JJ |
44 | You can match a range of values with `...`: |
45 | ||
9346a6ac | 46 | ```rust |
85aaf69f | 47 | let x = 1; |
1a4d82fc JJ |
48 | |
49 | match x { | |
50 | 1 ... 5 => println!("one through five"), | |
51 | _ => println!("anything"), | |
52 | } | |
53 | ``` | |
54 | ||
bd371182 AL |
55 | This prints `one through five`. |
56 | ||
57 | Ranges are mostly used with integers and `char`s: | |
58 | ||
59 | ```rust | |
60 | let x = '💅'; | |
61 | ||
62 | match x { | |
63 | 'a' ... 'j' => println!("early letter"), | |
64 | 'k' ... 'z' => println!("late letter"), | |
65 | _ => println!("something else"), | |
66 | } | |
67 | ``` | |
68 | ||
d9579d0f | 69 | This prints `something else`. |
1a4d82fc | 70 | |
9346a6ac AL |
71 | # Bindings |
72 | ||
bd371182 | 73 | You can bind values to names with `@`: |
1a4d82fc | 74 | |
9346a6ac | 75 | ```rust |
85aaf69f | 76 | let x = 1; |
1a4d82fc JJ |
77 | |
78 | match x { | |
79 | e @ 1 ... 5 => println!("got a range element {}", e), | |
80 | _ => println!("anything"), | |
81 | } | |
82 | ``` | |
83 | ||
bd371182 AL |
84 | This prints `got a range element 1`. This is useful when you want to |
85 | do a complicated match of part of a data structure: | |
86 | ||
87 | ```rust | |
88 | #[derive(Debug)] | |
89 | struct Person { | |
90 | name: Option<String>, | |
91 | } | |
92 | ||
93 | let name = "Steve".to_string(); | |
94 | let mut x: Option<Person> = Some(Person { name: Some(name) }); | |
95 | match x { | |
96 | Some(Person { name: ref a @ Some(_), .. }) => println!("{:?}", a), | |
97 | _ => {} | |
98 | } | |
99 | ``` | |
100 | ||
101 | This prints `Some("Steve")`: We’ve bound the inner `name` to `a`. | |
102 | ||
103 | If you use `@` with `|`, you need to make sure the name is bound in each part | |
104 | of the pattern: | |
105 | ||
106 | ```rust | |
107 | let x = 5; | |
108 | ||
109 | match x { | |
110 | e @ 1 ... 5 | e @ 8 ... 10 => println!("got a range element {}", e), | |
111 | _ => println!("anything"), | |
112 | } | |
113 | ``` | |
114 | ||
c1a9b12d | 115 | # Ignoring bindings |
9346a6ac | 116 | |
c1a9b12d SL |
117 | You can use `_` in a pattern to disregard the type and value. |
118 | For example, here’s a `match` against a `Result<T, E>`: | |
1a4d82fc | 119 | |
9346a6ac | 120 | ```rust |
c1a9b12d SL |
121 | # let some_value: Result<i32, &'static str> = Err("There was an error"); |
122 | match some_value { | |
123 | Ok(value) => println!("got a value: {}", value), | |
124 | Err(_) => println!("an error occurred"), | |
125 | } | |
126 | ``` | |
127 | ||
128 | In the first arm, we bind the value inside the `Ok` variant to `value`. But | |
129 | in the `Err` arm, we use `_` to disregard the specific error, and just print | |
130 | a general error message. | |
131 | ||
132 | `_` is valid in any pattern that creates a binding. This can be useful to | |
133 | ignore parts of a larger structure: | |
134 | ||
135 | ```rust | |
136 | fn coordinate() -> (i32, i32, i32) { | |
137 | // generate and return some sort of triple tuple | |
138 | # (1, 2, 3) | |
139 | } | |
140 | ||
141 | let (x, _, z) = coordinate(); | |
142 | ``` | |
143 | ||
144 | Here, we bind the first and last element of the tuple to `x` and `z`, but | |
145 | ignore the middle element. | |
146 | ||
147 | Similarly, you can use `..` in a pattern to disregard multiple values. | |
148 | ||
149 | ```rust | |
150 | enum OptionalTuple { | |
151 | Value(i32, i32, i32), | |
1a4d82fc JJ |
152 | Missing, |
153 | } | |
154 | ||
c1a9b12d | 155 | let x = OptionalTuple::Value(5, -2, 3); |
1a4d82fc JJ |
156 | |
157 | match x { | |
c1a9b12d SL |
158 | OptionalTuple::Value(..) => println!("Got a tuple!"), |
159 | OptionalTuple::Missing => println!("No such luck."), | |
1a4d82fc JJ |
160 | } |
161 | ``` | |
162 | ||
c1a9b12d | 163 | This prints `Got a tuple!`. |
bd371182 | 164 | |
9346a6ac AL |
165 | # Guards |
166 | ||
167 | You can introduce ‘match guards’ with `if`: | |
1a4d82fc | 168 | |
9346a6ac | 169 | ```rust |
1a4d82fc | 170 | enum OptionalInt { |
85aaf69f | 171 | Value(i32), |
1a4d82fc JJ |
172 | Missing, |
173 | } | |
174 | ||
85aaf69f | 175 | let x = OptionalInt::Value(5); |
1a4d82fc JJ |
176 | |
177 | match x { | |
178 | OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"), | |
179 | OptionalInt::Value(..) => println!("Got an int!"), | |
85aaf69f | 180 | OptionalInt::Missing => println!("No such luck."), |
1a4d82fc JJ |
181 | } |
182 | ``` | |
183 | ||
d9579d0f | 184 | This prints `Got an int!`. |
bd371182 | 185 | |
62682a34 SL |
186 | If you’re using `if` with multiple patterns, the `if` applies to both sides: |
187 | ||
188 | ```rust | |
189 | let x = 4; | |
190 | let y = false; | |
191 | ||
192 | match x { | |
193 | 4 | 5 if y => println!("yes"), | |
194 | _ => println!("no"), | |
195 | } | |
196 | ``` | |
197 | ||
198 | This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to | |
199 | just the `5`, In other words, the the precedence of `if` behaves like this: | |
200 | ||
201 | ```text | |
202 | (4 | 5) if y => ... | |
203 | ``` | |
204 | ||
205 | not this: | |
206 | ||
207 | ```text | |
208 | 4 | (5 if y) => ... | |
209 | ``` | |
210 | ||
9346a6ac | 211 | # ref and ref mut |
1a4d82fc | 212 | |
9346a6ac | 213 | If you want to get a [reference][ref], use the `ref` keyword: |
1a4d82fc | 214 | |
9346a6ac | 215 | ```rust |
85aaf69f | 216 | let x = 5; |
1a4d82fc JJ |
217 | |
218 | match x { | |
219 | ref r => println!("Got a reference to {}", r), | |
220 | } | |
221 | ``` | |
222 | ||
bd371182 AL |
223 | This prints `Got a reference to 5`. |
224 | ||
9346a6ac AL |
225 | [ref]: references-and-borrowing.html |
226 | ||
85aaf69f | 227 | Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref` |
1a4d82fc JJ |
228 | keyword _creates_ a reference, for use in the pattern. If you need a mutable |
229 | reference, `ref mut` will work in the same way: | |
230 | ||
9346a6ac | 231 | ```rust |
85aaf69f | 232 | let mut x = 5; |
1a4d82fc JJ |
233 | |
234 | match x { | |
235 | ref mut mr => println!("Got a mutable reference to {}", mr), | |
236 | } | |
237 | ``` | |
238 | ||
9346a6ac AL |
239 | # Destructuring |
240 | ||
bd371182 | 241 | If you have a compound data type, like a [`struct`][struct], you can destructure it |
9346a6ac | 242 | inside of a pattern: |
1a4d82fc | 243 | |
9346a6ac | 244 | ```rust |
1a4d82fc | 245 | struct Point { |
85aaf69f SL |
246 | x: i32, |
247 | y: i32, | |
1a4d82fc JJ |
248 | } |
249 | ||
85aaf69f | 250 | let origin = Point { x: 0, y: 0 }; |
1a4d82fc JJ |
251 | |
252 | match origin { | |
62682a34 | 253 | Point { x, y } => println!("({},{})", x, y), |
1a4d82fc JJ |
254 | } |
255 | ``` | |
256 | ||
bd371182 AL |
257 | [struct]: structs.html |
258 | ||
62682a34 SL |
259 | We can use `:` to give a value a different name. |
260 | ||
261 | ```rust | |
262 | struct Point { | |
263 | x: i32, | |
264 | y: i32, | |
265 | } | |
266 | ||
267 | let origin = Point { x: 0, y: 0 }; | |
268 | ||
269 | match origin { | |
270 | Point { x: x1, y: y1 } => println!("({},{})", x1, y1), | |
271 | } | |
272 | ``` | |
273 | ||
9346a6ac | 274 | If we only care about some of the values, we don’t have to give them all names: |
1a4d82fc | 275 | |
9346a6ac | 276 | ```rust |
1a4d82fc | 277 | struct Point { |
85aaf69f SL |
278 | x: i32, |
279 | y: i32, | |
1a4d82fc JJ |
280 | } |
281 | ||
85aaf69f | 282 | let origin = Point { x: 0, y: 0 }; |
1a4d82fc JJ |
283 | |
284 | match origin { | |
62682a34 | 285 | Point { x, .. } => println!("x is {}", x), |
1a4d82fc JJ |
286 | } |
287 | ``` | |
288 | ||
bd371182 AL |
289 | This prints `x is 0`. |
290 | ||
1a4d82fc JJ |
291 | You can do this kind of match on any member, not just the first: |
292 | ||
9346a6ac | 293 | ```rust |
1a4d82fc | 294 | struct Point { |
85aaf69f SL |
295 | x: i32, |
296 | y: i32, | |
1a4d82fc JJ |
297 | } |
298 | ||
85aaf69f | 299 | let origin = Point { x: 0, y: 0 }; |
1a4d82fc JJ |
300 | |
301 | match origin { | |
62682a34 | 302 | Point { y, .. } => println!("y is {}", y), |
1a4d82fc JJ |
303 | } |
304 | ``` | |
305 | ||
bd371182 AL |
306 | This prints `y is 0`. |
307 | ||
9346a6ac AL |
308 | This ‘destructuring’ behavior works on any compound data type, like |
309 | [tuples][tuples] or [enums][enums]. | |
1a4d82fc | 310 | |
9346a6ac AL |
311 | [tuples]: primitive-types.html#tuples |
312 | [enums]: enums.html | |
1a4d82fc | 313 | |
9346a6ac | 314 | # Mix and Match |
1a4d82fc | 315 | |
9346a6ac AL |
316 | Whew! That’s a lot of different ways to match things, and they can all be |
317 | mixed and matched, depending on what you’re doing: | |
1a4d82fc | 318 | |
bd371182 | 319 | ```rust,ignore |
1a4d82fc JJ |
320 | match x { |
321 | Foo { x: Some(ref name), y: None } => ... | |
322 | } | |
323 | ``` | |
324 | ||
bd371182 | 325 | Patterns are very powerful. Make good use of them. |