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