summary refs log tree commit diff
path: root/src/doc/trpl/patterns.md
blob: 4ebf696aa57a0b017cd70a063b00c3c7b7143990 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
% Patterns

We've made use of patterns a few times in the guide: first with `let` bindings,
then with `match` statements. Let's go on a whirlwind tour of all of the things
patterns can do!

A quick refresher: you can match against literals directly, and `_` acts as an
*any* case:

```{rust}
let x = 1;

match x {
    1 => println!("one"),
    2 => println!("two"),
    3 => println!("three"),
    _ => println!("anything"),
}
```

You can match multiple patterns with `|`:

```{rust}
let x = 1;

match x {
    1 | 2 => println!("one or two"),
    3 => println!("three"),
    _ => println!("anything"),
}
```

You can match a range of values with `...`:

```{rust}
let x = 1;

match x {
    1 ... 5 => println!("one through five"),
    _ => println!("anything"),
}
```

Ranges are mostly used with integers and single characters.

If you're matching multiple things, via a `|` or a `...`, you can bind
the value to a name with `@`:

```{rust}
let x = 1;

match x {
    e @ 1 ... 5 => println!("got a range element {}", e),
    _ => println!("anything"),
}
```

If you're matching on an enum which has variants, you can use `..` to
ignore the value and type in the variant:

```{rust}
enum OptionalInt {
    Value(i32),
    Missing,
}

let x = OptionalInt::Value(5);

match x {
    OptionalInt::Value(..) => println!("Got an int!"),
    OptionalInt::Missing => println!("No such luck."),
}
```

You can introduce *match guards* with `if`:

```{rust}
enum OptionalInt {
    Value(i32),
    Missing,
}

let x = OptionalInt::Value(5);

match x {
    OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"),
    OptionalInt::Value(..) => println!("Got an int!"),
    OptionalInt::Missing => println!("No such luck."),
}
```

If you're matching on a pointer, you can use the same syntax as you declared it
with. First, `&`:

```{rust}
let x = &5;

match x {
    &val => println!("Got a value: {}", val),
}
```

Here, the `val` inside the `match` has type `i32`. In other words, the left-hand
side of the pattern destructures the value. If we have `&5`, then in `&val`, `val`
would be `5`.

If you want to get a reference, use the `ref` keyword:

```{rust}
let x = 5;

match x {
    ref r => println!("Got a reference to {}", r),
}
```

Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref`
keyword _creates_ a reference, for use in the pattern. If you need a mutable
reference, `ref mut` will work in the same way:

```{rust}
let mut x = 5;

match x {
    ref mut mr => println!("Got a mutable reference to {}", mr),
}
```

If you have a struct, you can destructure it inside of a pattern:

```{rust}
# #![allow(non_shorthand_field_patterns)]
struct Point {
    x: i32,
    y: i32,
}

let origin = Point { x: 0, y: 0 };

match origin {
    Point { x: x, y: y } => println!("({},{})", x, y),
}
```

If we only care about some of the values, we don't have to give them all names:

```{rust}
# #![allow(non_shorthand_field_patterns)]
struct Point {
    x: i32,
    y: i32,
}

let origin = Point { x: 0, y: 0 };

match origin {
    Point { x: x, .. } => println!("x is {}", x),
}
```

You can do this kind of match on any member, not just the first:

```{rust}
# #![allow(non_shorthand_field_patterns)]
struct Point {
    x: i32,
    y: i32,
}

let origin = Point { x: 0, y: 0 };

match origin {
    Point { y: y, .. } => println!("y is {}", y),
}
```

If you want to match against a slice or array, you can use `&`:

```{rust}
# #![feature(slice_patterns)]
fn main() {
    let v = vec!["match_this", "1"];

    match &v[..] {
        ["match_this", second] => println!("The second element is {}", second),
        _ => {},
    }
}
```

Whew! That's a lot of different ways to match things, and they can all be
mixed and matched, depending on what you're doing:

```{rust,ignore}
match x {
    Foo { x: Some(ref name), y: None } => ...
}
```

Patterns are very powerful.  Make good use of them.