|
1 |
| -# Patterns |
2 |
| - |
3 |
| -We've actually used patterns a few times so far: they're used in `let` |
4 |
| -statements, in function parameters, and in the `match` expression. Patterns have |
5 |
| -a lot more abilities than we have demonstrated so far, so we'll cover some of |
6 |
| -the most commonly used ones in this section. Any of these abilities work in any |
7 |
| -place where a pattern is used. |
8 |
| - |
9 |
| -## `let` statements |
10 |
| - |
11 |
| -A basic `let` statement has this form: |
12 |
| - |
13 |
| -```text |
14 |
| -let PATTERN = EXPRESSION; |
15 |
| -``` |
16 |
| - |
17 |
| -We've seen statements like `let x = 5;` with a variable name in the `PATTERN` |
18 |
| -slot; a variable name is just a particularly humble form of pattern. |
19 |
| - |
20 |
| -Let’s try a more complex pattern. Change our example program to this: |
21 |
| - |
22 |
| -<span class="filename">Filename: src/main.rs</span> |
23 |
| - |
24 |
| -```rust |
25 |
| -fn main() { |
26 |
| - let (x, y) = (5, 6); |
27 |
| - |
28 |
| - println!("The value of x is: {}", x); |
29 |
| - println!("The value of y is: {}", y); |
30 |
| -} |
31 |
| -``` |
32 |
| - |
33 |
| -And run it with `cargo run`: |
34 |
| - |
35 |
| -```text |
36 |
| -$ cargo run |
37 |
| - Compiling patterns v0.1.0 (file:///projects/patterns) |
38 |
| - Running `target/debug/patterns` |
39 |
| -The value of x is: 5 |
40 |
| -The value of y is: 6 |
41 |
| -``` |
42 |
| - |
43 |
| -We’ve created two variables with one `let`! Here’s our pattern: |
44 |
| - |
45 |
| -```text |
46 |
| -(x, y) |
47 |
| -``` |
48 |
| - |
49 |
| -And here’s the value: |
50 |
| - |
51 |
| -```text |
52 |
| -(5, 6) |
53 |
| -``` |
54 |
| - |
55 |
| -As you can see, the two line up visually, and so `let` binds the variable `x` |
56 |
| -to the value `5` and `y` to `6`. We could have used two `let` statements as |
57 |
| -well: |
58 |
| - |
59 |
| -```rust |
60 |
| -fn main() { |
61 |
| - let x = 5; |
62 |
| - let y = 6; |
63 |
| -} |
64 |
| -``` |
65 |
| - |
66 |
| -In simple cases like this, two `let`s may be clearer, but in others, creating |
67 |
| -multiple variables at once is nice. As we become more proficient in Rust, we’ll |
68 |
| -figure out which style is better, but it’s mostly a judgment call. |
69 |
| - |
70 |
| -## Type annotations |
71 |
| - |
72 |
| -Most of the time, Rust uses *type inference*, meaning that it attempts to infer |
73 |
| -the types of your variables rather than you having to declare them explicitly |
74 |
| -even though Rust is a statically typed language. Occasionally, Rust won't have |
75 |
| -enough information to infer the type of your value, and you will need to add a |
76 |
| -type annotation in with the pattern. |
77 |
| - |
78 |
| -Here’s what a `let` statement with a *type annotation* looks like: |
79 |
| - |
80 |
| -```rust |
81 |
| -let x: i32 = 5; |
82 |
| -``` |
83 |
| - |
84 |
| -We can add a colon, followed by the type name. Here’s the structure of a `let` |
85 |
| -statement with a type annotation: |
86 |
| - |
87 |
| -```text |
88 |
| -let PATTERN: TYPE = VALUE; |
89 |
| -``` |
90 |
| - |
91 |
| -Note that the colon and the `TYPE` go *after* the `PATTERN`, not in the pattern |
92 |
| -itself. As an example, here’s our more complex pattern with two variables: |
93 |
| - |
94 |
| -```rust |
95 |
| -let (x, y): (i32, i32) = (5, 6); |
96 |
| -``` |
97 |
| - |
98 |
| -Just like we match up the `VALUE` with the `PATTERN`, we match up the `TYPE` |
99 |
| -with the `PATTERN`. |
100 |
| - |
101 |
| -## Literals & _ |
102 |
| - |
103 |
| -You can match against literals directly, and `_` acts as an any case: |
104 |
| - |
105 |
| -```rust |
106 |
| -let x = 1; |
107 |
| - |
108 |
| -match x { |
109 |
| - 1 => println!("one"), |
110 |
| - 2 => println!("two"), |
111 |
| - 3 => println!("three"), |
112 |
| - _ => println!("anything"), |
113 |
| -} |
114 |
| -``` |
115 |
| - |
116 |
| -This prints `one`. |
117 |
| - |
118 |
| -# Multiple patterns |
119 |
| - |
120 |
| -You can match multiple patterns with `|`: |
121 |
| - |
122 |
| -```rust |
123 |
| -let x = 1; |
124 |
| - |
125 |
| -match x { |
126 |
| - 1 | 2 => println!("one or two"), |
127 |
| - 3 => println!("three"), |
128 |
| - _ => println!("anything"), |
129 |
| -} |
130 |
| -``` |
131 |
| - |
132 |
| -This prints `one or two`. |
133 |
| - |
134 |
| -## ref and ref mut |
135 |
| - |
136 |
| -Usually, when you match against a pattern, variables are bound to a value. |
137 |
| -This means you'll end up moving the value into the `match`: |
138 |
| - |
139 |
| -```rust,ignore |
140 |
| -let name = Some(String::from("Bors")); |
141 |
| -
|
142 |
| -match name { |
143 |
| - Some(name) => println!("Found a name: {}", name), |
144 |
| - None => (), |
145 |
| -} |
146 |
| -
|
147 |
| -// name is moved here. This line will fail to compile: |
148 |
| -println!("name is: {:?}", name); |
149 |
| -``` |
150 |
| - |
151 |
| -If you'd prefer to bind `name` to a reference, use the `ref` keyword: |
152 |
| - |
153 |
| -```rust |
154 |
| -let name = Some(String::from("Bors")); |
155 |
| - |
156 |
| -match name { |
157 |
| - Some(ref name) => println!("Found a name: {}", name), |
158 |
| - None => (), |
159 |
| -} |
160 |
| - |
161 |
| -// name is not moved here; the match only took a reference to its data rather |
162 |
| -// than moving it. This will work: |
163 |
| -println!("name is: {:?}", name); |
164 |
| -``` |
165 |
| - |
166 |
| -And for a mutable reference, `ref mut`: |
167 |
| - |
168 |
| -```rust |
169 |
| -let mut name = Some(String::from("Bors")); |
170 |
| - |
171 |
| -match name { |
172 |
| - Some(ref mut name) => *name = String::from("Another name"), |
173 |
| - None => (), |
174 |
| -} |
175 |
| - |
176 |
| -// name is not moved here; the match only took a reference to its data rather |
177 |
| -// than moving it |
178 |
| -println!("name is: {:?}", name); |
179 |
| -``` |
180 |
| - |
181 |
| -## Destructuring |
182 |
| - |
183 |
| -Patterns can be used to destructure structs and enums: |
184 |
| - |
185 |
| -```rust |
186 |
| -struct Point { |
187 |
| - x: i32, |
188 |
| - y: i32, |
189 |
| -} |
190 |
| - |
191 |
| -let origin = Point { x: 0, y: 0 }; |
192 |
| - |
193 |
| -let Point { x, y } = origin; |
194 |
| -``` |
195 |
| - |
196 |
| -This brings `x` and `y` variables into scope, matching the `x` and `y` of |
197 |
| -`origin`. While it can be unusual in `let`, this is the same principle of |
198 |
| -patterns in `match`: |
199 |
| - |
200 |
| -```rust |
201 |
| -struct Point { |
202 |
| - x: i32, |
203 |
| - y: i32, |
204 |
| -} |
205 |
| - |
206 |
| -let origin = Point { x: 0, y: 0 }; |
207 |
| - |
208 |
| -match origin { |
209 |
| - Point { x, y } => { }, // variables x and y are created here |
210 |
| -} |
211 |
| -``` |
212 |
| - |
213 |
| -## Shadowing |
214 |
| - |
215 |
| -As with all variables, those declared by a pattern will shadow variables |
216 |
| -outside of the `match` construct: |
217 |
| - |
218 |
| -```rust |
219 |
| -let x = Some(5); |
220 |
| - |
221 |
| -match x { |
222 |
| - Some(x) => { }, // x is an i32 here, not an Option<i32> |
223 |
| - None => (), |
224 |
| -} |
225 |
| -``` |
226 |
| - |
227 |
| -## Ignoring values |
228 |
| - |
229 |
| -We discussed using `_` as a whole pattern to ignore it above, but you can |
230 |
| -also use `_` inside of another pattern to ignore just part of it: |
231 |
| - |
232 |
| -```rust |
233 |
| -let x = Some(5); |
234 |
| - |
235 |
| -match x { |
236 |
| - Some(_) => println!("got a Some and I don't care what's inside"), |
237 |
| - None => (), |
238 |
| -} |
239 |
| -``` |
240 |
| - |
241 |
| -Or like this: |
242 |
| - |
243 |
| -```rust |
244 |
| -let numbers = (2, 4, 8, 16, 32); |
245 |
| - |
246 |
| -match numbers { |
247 |
| - (first, _, third, _, fifth) => println!("Some numbers: {}, {}, {}", first, third, fifth), |
248 |
| -} |
249 |
| -``` |
250 |
| - |
251 |
| -If you want, you can use `..` to ignore all of the parts you haven't defined: |
252 |
| - |
253 |
| -```rust |
254 |
| -struct Point { |
255 |
| - x: i32, |
256 |
| - y: i32, |
257 |
| - z: i32, |
258 |
| -} |
259 |
| - |
260 |
| -let origin = Point { x: 0, y: 0, z: 0 }; |
261 |
| - |
262 |
| -match origin { |
263 |
| - Point { x, .. } => { }, // y and z are ignored |
264 |
| -} |
265 |
| -``` |
266 |
| - |
267 |
| -## Ranges |
268 |
| - |
269 |
| -You can match a range of values with `...`: |
270 |
| - |
271 |
| -```rust |
272 |
| -let x = 5; |
273 |
| - |
274 |
| -match x { |
275 |
| - 1 ... 5 => println!("one through five"), |
276 |
| - _ => println!("something else"), |
277 |
| -} |
278 |
| -``` |
279 |
| - |
280 |
| -Ranges are usually used with integers or `char`s: |
281 |
| - |
282 |
| -```rust |
283 |
| -let x = 'c'; |
284 |
| - |
285 |
| -match x { |
286 |
| - 'a' ... 'j' => println!("early ASCII letter"), |
287 |
| - 'k' ... 'z' => println!("late ASCII letter"), |
288 |
| - _ => println!("something else"), |
289 |
| -} |
290 |
| -``` |
291 |
| - |
292 |
| -## Guards |
293 |
| - |
294 |
| -You can introduce match guards with `if`: |
295 |
| - |
296 |
| -```rust |
297 |
| -let x = Some(5); |
298 |
| - |
299 |
| -match x { |
300 |
| - Some(x) if x < 5 => println!("less than five: {}", x), |
301 |
| - Some(x) => println!("{}", x), |
302 |
| - None => (), |
303 |
| -} |
304 |
| -``` |
305 |
| - |
306 |
| -If youre using if with multiple patterns, the if applies to both sides: |
307 |
| - |
308 |
| -```rust |
309 |
| -let x = 4; |
310 |
| -let y = false; |
311 |
| - |
312 |
| -match x { |
313 |
| - 4 | 5 if y => println!("yes"), |
314 |
| - _ => println!("no"), |
315 |
| -} |
316 |
| -``` |
317 |
| - |
318 |
| -This prints `no`, because the if applies to the whole of `4 | 5`, and not to only |
319 |
| -the `5`. In other words, the precedence of if behaves like this: |
320 |
| - |
321 |
| -```text |
322 |
| -(4 | 5) if y => ... |
323 |
| -``` |
324 |
| - |
325 |
| -not this: |
326 |
| - |
327 |
| -```text |
328 |
| -4 | (5 if y) => ... |
329 |
| -``` |
330 |
| - |
331 |
| -## Bindings |
332 |
| - |
333 |
| -You can bind values to names with `@`: |
| 1 | +# Patterns Match the Structure of Values |
| 2 | + |
| 3 | +Patterns are a special syntax within Rust for matching against the structure of |
| 4 | +our types, complex or simple. A pattern is made up of some combination of |
| 5 | +literals; destructured arrays, enums, structs, or tuples; variables, wildcards, |
| 6 | +and placeholders. These pieces describe the "shape" of the data we're working |
| 7 | +with. |
| 8 | + |
| 9 | +We use a pattern by taking some value and comparing it against the pattern. If |
| 10 | +the pattern matches our value, we do something with the value parts. Recall in |
| 11 | +Chapter 6 when we discussed the `match` expression that uses patterns like a |
| 12 | +coin sorting machine. We can name pieces within the shape, like we named the |
| 13 | +state that appeared on quarters in Chapter 6, and if the data fits the shape, |
| 14 | +we can use the named pieces. |
| 15 | + |
| 16 | +This chapter is a reference on all things related to patterns. We'll cover the |
| 17 | +valid places to use patterns, the difference between *refutable* and |
| 18 | +*irrefutable* patterns, and the different kinds of pattern syntax that you |
| 19 | +might see. |
0 commit comments