@@ -200,8 +200,62 @@ destructuring `let`, as we discussed previously in 'tuples.' In this case, the
200200## Enums
201201
202202Finally, Rust has a "sum type", an * enum* . Enums are an incredibly useful
203- feature of Rust, and are used throughout the standard library. This is an enum
204- that is provided by the Rust standard library:
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:
205259
206260``` {rust}
207261enum Ordering {
@@ -211,14 +265,9 @@ enum Ordering {
211265}
212266```
213267
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 ` :
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:
222271
223272``` {rust}
224273use std::cmp::Ordering;
@@ -245,11 +294,10 @@ fn main() {
245294}
246295```
247296
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.
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.
253301
254302Okay, let's talk about the actual code in the example. ` cmp ` is a function that
255303compares two things, and returns an ` Ordering ` . We return either
@@ -259,95 +307,44 @@ the two values are less, greater, or equal. Note that each variant of the
259307` Greater ` .
260308
261309The ` ordering ` variable has the type ` Ordering ` , and so contains one of the
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.
310+ three values. We then do a bunch of ` if ` /` else ` comparisons to check which
311+ one it is.
267312
268- This enum has two variants, one of which has a value:
313+ This ` Ordering::Greater ` notation is too long. Lets use ` use ` to import can
314+ the ` enum ` variants instead. This will avoid full scoping:
269315
270316``` {rust}
271- enum OptionalInt {
272- Value(i32),
273- Missing,
274- }
275- ```
276-
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:
317+ use std::cmp::Ordering::{self, Equal, Less, Greater};
283318
284- ``` {rust}
285- enum OptionalColor {
286- Color(i32, i32, i32),
287- Missing,
288- }
289- ```
290-
291- And you can also have something like this:
292-
293- ``` {rust}
294- enum StringResult {
295- StringOK(String),
296- ErrorReason(String),
319+ fn cmp(a: i32, b: i32) -> Ordering {
320+ if a < b { Less }
321+ else if a > b { Greater }
322+ else { Equal }
297323}
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.
303324
304- Here is an example of using our ` StringResult ` :
325+ fn main() {
326+ let x = 5;
327+ let y = 10;
305328
306- ``` rust
307- enum StringResult {
308- StringOK (String ),
309- ErrorReason (String ),
310- }
329+ let ordering = cmp(x, y); // ordering: Ordering
311330
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- }
331+ if ordering == Less { println!("less"); }
332+ else if ordering == Greater { println!("greater"); }
333+ else if ordering == Equal { println!("equal"); }
318334}
319335```
320336
321- That's a lot of typing! We can use the ` use ` keyword to make it shorter:
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.
322340
323- ``` rust
324- use StringResult :: StringOK ;
325- use StringResult :: ErrorReason ;
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.
326346
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- ```
342347
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.
348+ [ match ] : ./match.html
349+ [ game ] : ./guessing-game.html#comparing-guesses
350+ [ generics ] : ./generics.html
0 commit comments