@@ -200,62 +200,8 @@ destructuring `let`, as we discussed previously in 'tuples.' In this case, the
200
200
## Enums
201
201
202
202
Finally, Rust has a "sum type", an * enum* . Enums are an incredibly useful
203
- feature of Rust, and are used throughout the standard library. An ` enum ` is
204
- a type which ties a set of alternates to a specific name. For example, below
205
- we define ` Character ` to be either a ` Digit ` or something else. These
206
- can be used via their fully scoped names: ` Character::Other ` (more about ` :: `
207
- below).
208
-
209
- ``` rust
210
- enum Character {
211
- Digit (i32 ),
212
- Other ,
213
- }
214
- ```
215
-
216
- An ` enum ` variant can be defined as most normal types. Below are some example
217
- types have been listed which also would be allowed in an ` enum ` .
218
-
219
- ``` rust
220
- struct Empty ;
221
- struct Color (i32 , i32 , i32 );
222
- struct Length (i32 );
223
- struct Status { Health : i32 , Mana : i32 , Attack : i32 , Defense : i32 }
224
- struct HeightDatabase (Vec <i32 >);
225
- ```
226
-
227
- So you see that depending on the sub-datastructure, the ` enum ` variant, same as
228
- a struct, may or may not hold data. That is, in ` Character ` , ` Digit ` is a name
229
- tied to an ` i32 ` where ` Other ` is just a name. However, the fact that they are
230
- distinct makes this very useful.
231
-
232
- As with structures, enums don't by default have access to operators such as
233
- compare ( ` == ` and ` != ` ), binary operations (` * ` and ` + ` ), and order
234
- (` < ` and ` >= ` ). As such, using the previous ` Character ` type, the
235
- following code is invalid:
236
-
237
- ``` {rust,ignore}
238
- // These assignments both succeed
239
- let ten = Character::Digit(10);
240
- let four = Character::Digit(4);
241
-
242
- // Error: `*` is not implemented for type `Character`
243
- let forty = ten * four;
244
-
245
- // Error: `<=` is not implemented for type `Character`
246
- let four_is_smaller = four <= ten;
247
-
248
- // Error: `==` is not implemented for type `Character`
249
- let four_equals_ten = four == ten;
250
- ```
251
-
252
- This may seem rather limiting, particularly equality being invalid; in
253
- many cases however, it's unnecessary. Rust provides the [ ` match ` ] [ match ]
254
- keyword, which will be examined in more detail in the next section, which
255
- often allows better and easier branch control than a series of ` if ` /` else `
256
- statements would. However, for our [ game] [ game ] we need the comparisons
257
- to work so we will utilize the ` Ordering ` ` enum ` provided by the standard
258
- library which supports such comparisons. It has this form:
203
+ feature of Rust, and are used throughout the standard library. This is an enum
204
+ that is provided by the Rust standard library:
259
205
260
206
``` {rust}
261
207
enum Ordering {
@@ -265,9 +211,14 @@ enum Ordering {
265
211
}
266
212
```
267
213
268
- Because we did not define ` Ordering ` , we must import it (from the std
269
- library) with the ` use ` keyword. Here's an example of how ` Ordering ` is
270
- used:
214
+ An ` Ordering ` can only be _ one_ of ` Less ` , ` Equal ` , or ` Greater ` at any given
215
+ time.
216
+
217
+ Because ` Ordering ` is provided by the standard library, we can use the ` use `
218
+ keyword to use it in our code. We'll learn more about ` use ` later, but it's
219
+ used to bring names into scope.
220
+
221
+ Here's an example of how to use ` Ordering ` :
271
222
272
223
``` {rust}
273
224
use std::cmp::Ordering;
@@ -294,10 +245,11 @@ fn main() {
294
245
}
295
246
```
296
247
297
- The ` :: ` symbol is used to indicate a namespace. In this case, ` Ordering ` lives
298
- in the ` cmp ` submodule of the ` std ` module. We'll talk more about modules later
299
- in the guide. For now, all you need to know is that you can ` use ` things from
300
- the standard library if you need them.
248
+ There's a symbol here we haven't seen before: the double colon (` :: ` ).
249
+ This is used to indicate a namespace. In this case, ` Ordering ` lives in
250
+ the ` cmp ` submodule of the ` std ` module. We'll talk more about modules
251
+ later in the guide. For now, all you need to know is that you can ` use `
252
+ things from the standard library if you need them.
301
253
302
254
Okay, let's talk about the actual code in the example. ` cmp ` is a function that
303
255
compares two things, and returns an ` Ordering ` . We return either
@@ -307,44 +259,95 @@ the two values are less, greater, or equal. Note that each variant of the
307
259
` Greater ` .
308
260
309
261
The ` ordering ` variable has the type ` Ordering ` , and so contains one of the
310
- three values. We then do a bunch of ` if ` /` else ` comparisons to check which
311
- one it is.
262
+ three values. We can then do a bunch of ` if ` /` else ` comparisons to check which
263
+ one it is. However, repeated ` if ` /` else ` comparisons get quite tedious. Rust
264
+ has a feature that not only makes them nicer to read, but also makes sure that
265
+ you never miss a case. Before we get to that, though, let's talk about another
266
+ kind of enum: one with values.
312
267
313
- This ` Ordering::Greater ` notation is too long. Lets use ` use ` to import can
314
- the ` enum ` variants instead. This will avoid full scoping:
268
+ This enum has two variants, one of which has a value:
315
269
316
270
``` {rust}
317
- use std::cmp::Ordering::{self, Equal, Less, Greater};
271
+ enum OptionalInt {
272
+ Value(i32),
273
+ Missing,
274
+ }
275
+ ```
318
276
319
- fn cmp(a: i32, b: i32) -> Ordering {
320
- if a < b { Less }
321
- else if a > b { Greater }
322
- else { Equal }
277
+ This enum represents an ` i32 ` that we may or may not have. In the ` Missing `
278
+ case, we have no value, but in the ` Value ` case, we do. This enum is specific
279
+ to ` i32 ` s, though. We can make it usable by any type, but we haven't quite
280
+ gotten there yet!
281
+
282
+ You can also have any number of values in an enum:
283
+
284
+ ``` {rust}
285
+ enum OptionalColor {
286
+ Color(i32, i32, i32),
287
+ Missing,
323
288
}
289
+ ```
324
290
325
- fn main() {
326
- let x = 5;
327
- let y = 10;
291
+ And you can also have something like this:
328
292
329
- let ordering = cmp(x, y); // ordering: Ordering
293
+ ``` {rust}
294
+ enum StringResult {
295
+ StringOK(String),
296
+ ErrorReason(String),
297
+ }
298
+ ```
299
+ Where a ` StringResult ` is either a ` StringResult::StringOK ` , with the result of
300
+ a computation, or a ` StringResult::ErrorReason ` with a ` String ` explaining
301
+ what caused the computation to fail. These kinds of ` enum ` s are actually very
302
+ useful and are even part of the standard library.
303
+
304
+ Here is an example of using our ` StringResult ` :
330
305
331
- if ordering == Less { println!("less"); }
332
- else if ordering == Greater { println!("greater"); }
333
- else if ordering == Equal { println!("equal"); }
306
+ ``` rust
307
+ enum StringResult {
308
+ StringOK (String ),
309
+ ErrorReason (String ),
310
+ }
311
+
312
+ fn respond (greeting : & str ) -> StringResult {
313
+ if greeting == " Hello" {
314
+ StringResult :: StringOK (" Good morning!" . to_string ())
315
+ } else {
316
+ StringResult :: ErrorReason (" I didn't understand you!" . to_string ())
317
+ }
334
318
}
335
319
```
336
320
337
- Importing variants is convenient and compact, but can also cause name conflicts,
338
- so do this with caution. It's considered good style to rarely import variants
339
- for this reason.
321
+ That's a lot of typing! We can use the ` use ` keyword to make it shorter:
340
322
341
- As you can see, ` enum ` s are quite a powerful tool for data representation, and are
342
- even more useful when they're [ generic] [ generics ] across types. Before we
343
- get to generics, though, let's talk about how to use them with pattern matching, a
344
- tool that will let us deconstruct this sum type (the type theory term for enums)
345
- in a very elegant way and avoid all these messy ` if ` /` else ` s.
323
+ ``` rust
324
+ use StringResult :: StringOK ;
325
+ use StringResult :: ErrorReason ;
346
326
327
+ enum StringResult {
328
+ StringOK (String ),
329
+ ErrorReason (String ),
330
+ }
331
+
332
+ # fn main () {}
333
+
334
+ fn respond (greeting : & str ) -> StringResult {
335
+ if greeting == " Hello" {
336
+ StringOK (" Good morning!" . to_string ())
337
+ } else {
338
+ ErrorReason (" I didn't understand you!" . to_string ())
339
+ }
340
+ }
341
+ ```
347
342
348
- [ match ] : ./match.html
349
- [ game ] : ./guessing-game.html#comparing-guesses
350
- [ generics ] : ./generics.html
343
+ ` use ` declarations must come before anything else, which looks a little strange in this example,
344
+ since we ` use ` the variants before we define them. Anyway, in the body of ` respond ` , we can just
345
+ say ` StringOK ` now, rather than the full ` StringResult::StringOK ` . Importing variants can be
346
+ convenient, but can also cause name conflicts, so do this with caution. It's considered good style
347
+ to rarely import variants for this reason.
348
+
349
+ As you can see, ` enum ` s with values are quite a powerful tool for data representation,
350
+ and can be even more useful when they're generic across types. Before we get to generics,
351
+ though, let's talk about how to use them with pattern matching, a tool that will
352
+ let us deconstruct this sum type (the type theory term for enums) in a very elegant
353
+ way and avoid all these messy ` if ` /` else ` s.
0 commit comments