]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | % Patterns |
2 | ||
9346a6ac | 3 | Patterns are quite common in Rust. We use them in [variable |
54a0048b | 4 | bindings][bindings], [match expressions][match], and other places, too. Let’s go |
9346a6ac AL |
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 | ||
b039eaaf SL |
26 | There’s one pitfall with patterns: like anything that introduces a new binding, |
27 | they introduce shadowing. For example: | |
28 | ||
29 | ```rust | |
9cc50fc6 | 30 | let x = 1; |
b039eaaf SL |
31 | let c = 'c'; |
32 | ||
33 | match c { | |
34 | x => println!("x: {} c: {}", x, c), | |
35 | } | |
36 | ||
37 | println!("x: {}", x) | |
38 | ``` | |
39 | ||
40 | This prints: | |
41 | ||
42 | ```text | |
43 | x: c c: c | |
9cc50fc6 | 44 | x: 1 |
b039eaaf SL |
45 | ``` |
46 | ||
47 | In other words, `x =>` matches the pattern and introduces a new binding named | |
9cc50fc6 SL |
48 | `x`. This new binding is in scope for the match arm and takes on the value of |
49 | `c`. Notice that the value of `x` outside the scope of the match has no bearing | |
50 | on the value of `x` within it. Because we already have a binding named `x`, this | |
51 | new `x` shadows it. | |
b039eaaf | 52 | |
9346a6ac AL |
53 | # Multiple patterns |
54 | ||
1a4d82fc JJ |
55 | You can match multiple patterns with `|`: |
56 | ||
9346a6ac | 57 | ```rust |
85aaf69f | 58 | let x = 1; |
1a4d82fc JJ |
59 | |
60 | match x { | |
61 | 1 | 2 => println!("one or two"), | |
62 | 3 => println!("three"), | |
63 | _ => println!("anything"), | |
64 | } | |
65 | ``` | |
66 | ||
bd371182 AL |
67 | This prints `one or two`. |
68 | ||
e9174d1e | 69 | # Destructuring |
9346a6ac | 70 | |
e9174d1e SL |
71 | If you have a compound data type, like a [`struct`][struct], you can destructure it |
72 | inside of a pattern: | |
1a4d82fc | 73 | |
9346a6ac | 74 | ```rust |
e9174d1e SL |
75 | struct Point { |
76 | x: i32, | |
77 | y: i32, | |
1a4d82fc | 78 | } |
bd371182 | 79 | |
e9174d1e | 80 | let origin = Point { x: 0, y: 0 }; |
bd371182 | 81 | |
e9174d1e SL |
82 | match origin { |
83 | Point { x, y } => println!("({},{})", x, y), | |
bd371182 AL |
84 | } |
85 | ``` | |
86 | ||
e9174d1e | 87 | [struct]: structs.html |
9346a6ac | 88 | |
e9174d1e | 89 | We can use `:` to give a value a different name. |
1a4d82fc | 90 | |
9346a6ac | 91 | ```rust |
e9174d1e SL |
92 | struct Point { |
93 | x: i32, | |
94 | y: i32, | |
95 | } | |
1a4d82fc | 96 | |
e9174d1e SL |
97 | let origin = Point { x: 0, y: 0 }; |
98 | ||
99 | match origin { | |
100 | Point { x: x1, y: y1 } => println!("({},{})", x1, y1), | |
1a4d82fc JJ |
101 | } |
102 | ``` | |
103 | ||
e9174d1e | 104 | If we only care about some of the values, we don’t have to give them all names: |
bd371182 AL |
105 | |
106 | ```rust | |
e9174d1e SL |
107 | struct Point { |
108 | x: i32, | |
109 | y: i32, | |
bd371182 AL |
110 | } |
111 | ||
5bcae85e | 112 | let point = Point { x: 2, y: 3 }; |
e9174d1e | 113 | |
5bcae85e | 114 | match point { |
e9174d1e | 115 | Point { x, .. } => println!("x is {}", x), |
bd371182 AL |
116 | } |
117 | ``` | |
118 | ||
5bcae85e | 119 | This prints `x is 2`. |
bd371182 | 120 | |
9cc50fc6 | 121 | You can do this kind of match on any member, not only the first: |
bd371182 AL |
122 | |
123 | ```rust | |
e9174d1e SL |
124 | struct Point { |
125 | x: i32, | |
126 | y: i32, | |
127 | } | |
bd371182 | 128 | |
5bcae85e | 129 | let point = Point { x: 2, y: 3 }; |
e9174d1e | 130 | |
5bcae85e | 131 | match point { |
e9174d1e | 132 | Point { y, .. } => println!("y is {}", y), |
bd371182 AL |
133 | } |
134 | ``` | |
135 | ||
5bcae85e | 136 | This prints `y is 3`. |
e9174d1e SL |
137 | |
138 | This ‘destructuring’ behavior works on any compound data type, like | |
139 | [tuples][tuples] or [enums][enums]. | |
140 | ||
141 | [tuples]: primitive-types.html#tuples | |
142 | [enums]: enums.html | |
143 | ||
c1a9b12d | 144 | # Ignoring bindings |
9346a6ac | 145 | |
c1a9b12d SL |
146 | You can use `_` in a pattern to disregard the type and value. |
147 | For example, here’s a `match` against a `Result<T, E>`: | |
1a4d82fc | 148 | |
9346a6ac | 149 | ```rust |
c1a9b12d SL |
150 | # let some_value: Result<i32, &'static str> = Err("There was an error"); |
151 | match some_value { | |
152 | Ok(value) => println!("got a value: {}", value), | |
153 | Err(_) => println!("an error occurred"), | |
154 | } | |
155 | ``` | |
156 | ||
157 | In the first arm, we bind the value inside the `Ok` variant to `value`. But | |
9cc50fc6 | 158 | in the `Err` arm, we use `_` to disregard the specific error, and print |
c1a9b12d SL |
159 | a general error message. |
160 | ||
161 | `_` is valid in any pattern that creates a binding. This can be useful to | |
162 | ignore parts of a larger structure: | |
163 | ||
164 | ```rust | |
165 | fn coordinate() -> (i32, i32, i32) { | |
166 | // generate and return some sort of triple tuple | |
167 | # (1, 2, 3) | |
168 | } | |
169 | ||
170 | let (x, _, z) = coordinate(); | |
171 | ``` | |
172 | ||
173 | Here, we bind the first and last element of the tuple to `x` and `z`, but | |
174 | ignore the middle element. | |
175 | ||
7453a54e | 176 | It’s worth noting that using `_` never binds the value in the first place, |
3157f602 | 177 | which means that the value does not move: |
7453a54e SL |
178 | |
179 | ```rust | |
180 | let tuple: (u32, String) = (5, String::from("five")); | |
181 | ||
182 | // Here, tuple is moved, because the String moved: | |
183 | let (x, _s) = tuple; | |
184 | ||
185 | // The next line would give "error: use of partially moved value: `tuple`" | |
186 | // println!("Tuple is: {:?}", tuple); | |
187 | ||
188 | // However, | |
189 | ||
190 | let tuple = (5, String::from("five")); | |
191 | ||
192 | // Here, tuple is _not_ moved, as the String was never moved, and u32 is Copy: | |
193 | let (x, _) = tuple; | |
194 | ||
195 | // That means this works: | |
196 | println!("Tuple is: {:?}", tuple); | |
197 | ``` | |
198 | ||
199 | This also means that any temporary variables will be dropped at the end of the | |
200 | statement: | |
201 | ||
202 | ```rust | |
203 | // Here, the String created will be dropped immediately, as it’s not bound: | |
204 | ||
205 | let _ = String::from(" hello ").trim(); | |
206 | ``` | |
207 | ||
208 | You can also use `..` in a pattern to disregard multiple values: | |
c1a9b12d SL |
209 | |
210 | ```rust | |
211 | enum OptionalTuple { | |
212 | Value(i32, i32, i32), | |
1a4d82fc JJ |
213 | Missing, |
214 | } | |
215 | ||
c1a9b12d | 216 | let x = OptionalTuple::Value(5, -2, 3); |
1a4d82fc JJ |
217 | |
218 | match x { | |
c1a9b12d SL |
219 | OptionalTuple::Value(..) => println!("Got a tuple!"), |
220 | OptionalTuple::Missing => println!("No such luck."), | |
1a4d82fc JJ |
221 | } |
222 | ``` | |
223 | ||
c1a9b12d | 224 | This prints `Got a tuple!`. |
bd371182 | 225 | |
e9174d1e | 226 | # ref and ref mut |
9346a6ac | 227 | |
e9174d1e | 228 | If you want to get a [reference][ref], use the `ref` keyword: |
1a4d82fc | 229 | |
9346a6ac | 230 | ```rust |
e9174d1e | 231 | let x = 5; |
1a4d82fc JJ |
232 | |
233 | match x { | |
e9174d1e | 234 | ref r => println!("Got a reference to {}", r), |
1a4d82fc JJ |
235 | } |
236 | ``` | |
237 | ||
e9174d1e | 238 | This prints `Got a reference to 5`. |
bd371182 | 239 | |
e9174d1e SL |
240 | [ref]: references-and-borrowing.html |
241 | ||
242 | Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref` | |
243 | keyword _creates_ a reference, for use in the pattern. If you need a mutable | |
244 | reference, `ref mut` will work in the same way: | |
62682a34 SL |
245 | |
246 | ```rust | |
e9174d1e | 247 | let mut x = 5; |
62682a34 SL |
248 | |
249 | match x { | |
e9174d1e | 250 | ref mut mr => println!("Got a mutable reference to {}", mr), |
62682a34 SL |
251 | } |
252 | ``` | |
253 | ||
e9174d1e | 254 | # Ranges |
62682a34 | 255 | |
e9174d1e | 256 | You can match a range of values with `...`: |
62682a34 | 257 | |
e9174d1e SL |
258 | ```rust |
259 | let x = 1; | |
62682a34 | 260 | |
e9174d1e SL |
261 | match x { |
262 | 1 ... 5 => println!("one through five"), | |
263 | _ => println!("anything"), | |
264 | } | |
62682a34 SL |
265 | ``` |
266 | ||
e9174d1e | 267 | This prints `one through five`. |
1a4d82fc | 268 | |
e9174d1e | 269 | Ranges are mostly used with integers and `char`s: |
1a4d82fc | 270 | |
9346a6ac | 271 | ```rust |
e9174d1e | 272 | let x = '💅'; |
1a4d82fc JJ |
273 | |
274 | match x { | |
e9174d1e SL |
275 | 'a' ... 'j' => println!("early letter"), |
276 | 'k' ... 'z' => println!("late letter"), | |
277 | _ => println!("something else"), | |
1a4d82fc JJ |
278 | } |
279 | ``` | |
280 | ||
e9174d1e | 281 | This prints `something else`. |
bd371182 | 282 | |
e9174d1e | 283 | # Bindings |
9346a6ac | 284 | |
e9174d1e | 285 | You can bind values to names with `@`: |
1a4d82fc | 286 | |
9346a6ac | 287 | ```rust |
e9174d1e | 288 | let x = 1; |
1a4d82fc JJ |
289 | |
290 | match x { | |
e9174d1e SL |
291 | e @ 1 ... 5 => println!("got a range element {}", e), |
292 | _ => println!("anything"), | |
1a4d82fc JJ |
293 | } |
294 | ``` | |
295 | ||
e9174d1e SL |
296 | This prints `got a range element 1`. This is useful when you want to |
297 | do a complicated match of part of a data structure: | |
1a4d82fc | 298 | |
9346a6ac | 299 | ```rust |
e9174d1e SL |
300 | #[derive(Debug)] |
301 | struct Person { | |
302 | name: Option<String>, | |
1a4d82fc JJ |
303 | } |
304 | ||
e9174d1e | 305 | let name = "Steve".to_string(); |
7453a54e | 306 | let x: Option<Person> = Some(Person { name: Some(name) }); |
e9174d1e SL |
307 | match x { |
308 | Some(Person { name: ref a @ Some(_), .. }) => println!("{:?}", a), | |
309 | _ => {} | |
1a4d82fc JJ |
310 | } |
311 | ``` | |
312 | ||
e9174d1e | 313 | This prints `Some("Steve")`: we’ve bound the inner `name` to `a`. |
bd371182 | 314 | |
e9174d1e SL |
315 | If you use `@` with `|`, you need to make sure the name is bound in each part |
316 | of the pattern: | |
62682a34 SL |
317 | |
318 | ```rust | |
e9174d1e | 319 | let x = 5; |
62682a34 | 320 | |
e9174d1e SL |
321 | match x { |
322 | e @ 1 ... 5 | e @ 8 ... 10 => println!("got a range element {}", e), | |
323 | _ => println!("anything"), | |
62682a34 SL |
324 | } |
325 | ``` | |
326 | ||
e9174d1e SL |
327 | # Guards |
328 | ||
329 | You can introduce ‘match guards’ with `if`: | |
1a4d82fc | 330 | |
9346a6ac | 331 | ```rust |
e9174d1e SL |
332 | enum OptionalInt { |
333 | Value(i32), | |
334 | Missing, | |
1a4d82fc JJ |
335 | } |
336 | ||
e9174d1e | 337 | let x = OptionalInt::Value(5); |
1a4d82fc | 338 | |
e9174d1e SL |
339 | match x { |
340 | OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"), | |
341 | OptionalInt::Value(..) => println!("Got an int!"), | |
342 | OptionalInt::Missing => println!("No such luck."), | |
1a4d82fc JJ |
343 | } |
344 | ``` | |
345 | ||
e9174d1e | 346 | This prints `Got an int!`. |
bd371182 | 347 | |
e9174d1e | 348 | If you’re using `if` with multiple patterns, the `if` applies to both sides: |
1a4d82fc | 349 | |
9346a6ac | 350 | ```rust |
e9174d1e SL |
351 | let x = 4; |
352 | let y = false; | |
1a4d82fc | 353 | |
e9174d1e SL |
354 | match x { |
355 | 4 | 5 if y => println!("yes"), | |
356 | _ => println!("no"), | |
1a4d82fc JJ |
357 | } |
358 | ``` | |
359 | ||
e9174d1e | 360 | This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to |
9cc50fc6 | 361 | only the `5`. In other words, the precedence of `if` behaves like this: |
bd371182 | 362 | |
e9174d1e SL |
363 | ```text |
364 | (4 | 5) if y => ... | |
365 | ``` | |
1a4d82fc | 366 | |
e9174d1e SL |
367 | not this: |
368 | ||
369 | ```text | |
370 | 4 | (5 if y) => ... | |
371 | ``` | |
1a4d82fc | 372 | |
9346a6ac | 373 | # Mix and Match |
1a4d82fc | 374 | |
9346a6ac AL |
375 | Whew! That’s a lot of different ways to match things, and they can all be |
376 | mixed and matched, depending on what you’re doing: | |
1a4d82fc | 377 | |
bd371182 | 378 | ```rust,ignore |
1a4d82fc JJ |
379 | match x { |
380 | Foo { x: Some(ref name), y: None } => ... | |
381 | } | |
382 | ``` | |
383 | ||
bd371182 | 384 | Patterns are very powerful. Make good use of them. |