]> git.proxmox.com Git - rustc.git/blob - src/doc/book/nostarch/chapter02.md
New upstream version 1.58.1+dfsg1
[rustc.git] / src / doc / book / nostarch / chapter02.md
1
2 [TOC]
3
4 # Programming a Guessing Game
5
6 Let’s jump into Rust by working through a hands-on project together! This
7 chapter introduces you to a few common Rust concepts by showing you how to use
8 them in a real program. You’ll learn about `let`, `match`, methods, associated
9 functions, using external crates, and more! In the following chapters, we’ll
10 explore these ideas in more detail. In this chapter, you’ll practice the
11 fundamentals.
12
13 We’ll implement a classic beginner programming problem: a guessing game. Here’s
14 how it works: the program will generate a random integer between 1 and 100. It
15 will then prompt the player to enter a guess. After a guess is entered, the
16 program will indicate whether the guess is too low or too high. If the guess is
17 correct, the game will print a congratulatory message and exit.
18
19 ## Setting Up a New Project
20
21 To set up a new project, go to the *projects* directory that you created in
22 Chapter 1 and make a new project using Cargo, like so:
23
24 ```
25 $ cargo new guessing_game
26 $ cd guessing_game
27 ```
28
29 The first command, `cargo new`, takes the name of the project (`guessing_game`)
30 as the first argument. The second command changes to the new project’s
31 directory.
32
33 Look at the generated *Cargo.toml* file:
34
35 Filename: Cargo.toml
36
37 ```
38 [package]
39 name = "guessing_game"
40 version = "0.1.0"
41 edition = "2018"
42
43
44 [dependencies]
45 ```
46
47 As you saw in Chapter 1, `cargo new` generates a “Hello, world!” program for
48 you. Check out the *src/main.rs* file:
49
50 Filename: src/main.rs
51
52 ```
53 fn main() {
54 println!("Hello, world!");
55 }
56 ```
57
58 Now let’s compile this “Hello, world!” program and run it in the same step
59 using the `cargo run` command:
60
61 ```
62 $ cargo run
63 Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
64 Finished dev [unoptimized + debuginfo] target(s) in 1.50s
65 Running `target/debug/guessing_game`
66 Hello, world!
67 ```
68
69 The `run` command comes in handy when you need to rapidly iterate on a project,
70 as we’ll do in this game, quickly testing each iteration before moving on to
71 the next one.
72
73 Reopen the *src/main.rs* file. You’ll be writing all the code in this file.
74
75 ## Processing a Guess
76
77 The first part of the guessing game program will ask for user input, process
78 that input, and check that the input is in the expected form. To start, we’ll
79 allow the player to input a guess. Enter the code in Listing 2-1 into
80 *src/main.rs*.
81
82 Filename: src/main.rs
83
84 ```
85 use std::io;
86
87 fn main() {
88 println!("Guess the number!");
89
90 println!("Please input your guess.");
91
92 let mut guess = String::new();
93
94 io::stdin()
95 .read_line(&mut guess)
96 .expect("Failed to read line");
97
98 println!("You guessed: {}", guess);
99 }
100 ```
101
102 Listing 2-1: Code that gets a guess from the user and prints it
103
104 This code contains a lot of information, so let’s go over it line by line. To
105 obtain user input and then print the result as output, we need to bring the
106 `io` input/output library into scope. The `io` library comes from the
107 standard library, known as `std`:
108
109 ```
110 use std::io;
111 ```
112
113 By default, Rust has a few items defined in the standard library that it brings
114 into the scope of every program. This set is called the *prelude*, and you can
115 see everything in it at *https://doc.rust-lang.org/std/prelude/index.html*.
116
117 <!-- I think it'd be worth giving a really quick direct definition of the
118 prelude here, since it's the first time it's mentioned in the book (unless this
119 time around you want to mention it earlier?)-- /LC-->
120 <!-- Done! /Carol -->
121
122 If a type you want to use isn’t in the prelude, you have to bring that type
123 into scope explicitly with a `use` statement. Using the `std::io` library
124 provides you with a number of useful features, including the ability to accept
125 user input.
126
127 As you saw in Chapter 1, the `main` function is the entry point into the
128 program:
129
130 ```
131 fn main() {
132 ```
133
134 The `fn` syntax declares a new function, the parentheses, `()`, indicate there
135 are no parameters, and the curly bracket, `{`, starts the body of the function.
136
137 As you also learned in Chapter 1, `println!` is a macro that prints a string to
138 the screen:
139
140 ```
141 println!("Guess the number!");
142
143 println!("Please input your guess.");
144 ```
145
146 This code is printing a prompt stating what the game is and requesting input
147 from the user.
148
149 ### Storing Values with Variables
150
151 Next, we’ll create a *variable* to store the user input, like this:
152
153 ```
154 let mut guess = String::new();
155 ```
156
157 Now the program is getting interesting! There’s a lot going on in this little
158 line. We use the `let` statement to create the variable. Here’s another example:
159
160 ```
161 let apples = 5;
162 ```
163
164 This line creates a new variable named `apples` and binds it to the value 5. In
165 Rust, variables are immutable by default. We’ll be discussing this concept in
166 detail in the “Variables and Mutability” section in Chapter 3. To make a
167 variable mutable, we add `mut` before the variable name:
168
169 ```
170 let apples = 5; // immutable
171 let mut bananas = 5; // mutable
172 ```
173
174 > Note: The `//` syntax starts a comment that continues until the end of the
175 > line. Rust ignores everything in comments. We’ll discuss comments in more
176 > detail in Chapter 3.
177
178 Returning to the guessing game program, you now know that `let mut guess` will
179 introduce a mutable variable named `guess`. The equal sign (`=`) tells Rust we
180 want to bind something to the variable now. On the right of the equals sign is
181 the value that `guess` is bound to, which is the result of calling
182 `String::new`, a function that returns a new instance of a `String`. `String`
183 is a string type provided by the standard library that is a growable, UTF-8
184 encoded bit of text.
185
186 The `::` syntax in the `::new` line indicates that `new` is an associated
187 function of the `String` type. An *associated function* is a function that’s
188 implemented on a type, in this case `String`. This `new` function creates a
189 new, empty string. You’ll find a `new` function on many types, because it’s a
190 common name for a function that makes a new value of some kind.
191
192 In full, the `let mut guess = String::new();` line has created a mutable
193 variable that is currently bound to a new, empty instance of a `String`. Whew!
194
195 ### Receiving User Input
196
197 Recall that we included the input/output functionality from the standard
198 library with `use std::io;` on the first line of the program. Now we’ll call
199 the `stdin` function from the `io` module, which will allow us to handle user
200 input:
201
202 ```
203 io::stdin()
204 .read_line(&mut guess)
205 ```
206
207 If we hadn’t imported the `io` library with `use std::io` at the beginning of
208 the program, we could still use the function by writing this function call as
209 `std::io::stdin`. The `stdin` function returns an instance of `std::io::Stdin`,
210 which is a type that represents a handle to the standard input for your
211 terminal.
212
213 Next, the line `.read_line(&mut guess)` calls the `read_line` method on the
214 standard input handle to get input from the user. We’re also passing `&mut
215 guess` as the argument to `read_line` to tell it what string to store the user
216 input in. The full job of `read_line` is to take whatever the user types into
217 standard input
218
219 <!--- can you check my edits here? I wanted to make the purpose of passing the
220 variable we made earlier in clearer /:C -->
221 <!-- Yup, looks good! /Carol -->
222
223 and append that into a string (without overwriting its contents), so we
224 therefore pass that string as an argument. The string argument needs to be
225 mutable so the method can change the string’s content.
226
227 The `&` indicates that this argument is a *reference*, which gives you a way to
228 let multiple parts of your code access one piece of data without needing to
229 copy that data into memory multiple times. References are a complex feature,
230 and one of Rust’s major advantages is how safe and easy it is to use
231 references. You don’t need to know a lot of those details to finish this
232 program. For now, all you need to know is that like variables, references are
233 immutable by default. Hence, you need to write `&mut guess` rather than
234 `&guess` to make it mutable. (Chapter 4 will explain references more
235 thoroughly.)
236
237 ### Handling Potential Failure with the `Result` Type
238
239 We’re still working on this line of code. Although we’re now discussing a third
240 <!--- in the program this is the second line of code -- do you mean the third
241 section of this line? -->
242 <!-- This is still discussing the code in Listing 2-1, and is going to talk
243 about the third line, if you're counting the lines of the page, of this logical
244 line of code, where logical lines of code are ended with semicolons. Do you
245 have suggestions on how to make that clearer? /Carol -->
246
247 line of text, it’s still part of a single logical line of code. The next part
248 is this method:
249
250 ```
251 .expect("Failed to read line");
252 ```
253
254 We could have written this code as:
255
256 ```
257 io::stdin().read_line(&mut guess).expect("Failed to read line");
258 ```
259
260 However, one long line is difficult to read, so it’s best to divide it. It’s
261 often wise to introduce a newline and other whitespace to help break up long
262 lines when you call a method with the `.method_name()` syntax. Now let’s
263 discuss what this line does.
264
265 As mentioned earlier, `read_line` puts whatever the user enters into the string
266 we pass to it, but it also returns a value—in this case, an `io::Result`. Rust
267 has a number of types named `Result` in its standard library: a generic
268 `Result` as well as specific versions for submodules, such as `io::Result`. The
269 `Result` types are *enumerations*, often referred to as *enums*, which can have
270 a fixed set of possibilites known as *variants*. Enums are often used with
271 `match`, a conditional that makes it convenient to execute different code based
272 on which variant an enum value is when the conditional is evaluated.
273
274 <!--- I wanted to give an indication of the purpose of variants, is my addition
275 (the last sentence) fair to say? /LC -->
276 <!-- Not quite, I edited a bit-- did I make it better or worse? :) /Carol -->
277
278 Chapter 6 will cover enums in more detail. The purpose of these `Result` types
279 is to encode error-handling information.
280
281 `Result`’s variants are `Ok` or `Err`. The `Ok` variant indicates the
282 operation was successful, and inside `Ok` is the successfully generated value.
283 The `Err` variant means the operation failed, and `Err` contains information
284 about how or why the operation failed.
285
286 Values of the `Result` type, like values of any type, have methods defined on
287 them. An instance of `io::Result` has an `expect` method that you can call. If
288 this instance of `io::Result` is an `Err` value, `expect` will cause the
289 program to crash and display the message that you passed as an argument to
290 `expect`. If the `read_line` method returns an `Err`, it would likely be the
291 result of an error coming from the underlying operating system. If this
292 instance of `io::Result` is an `Ok` value, `expect` will take the return value
293 that `Ok` is holding and return just that value to you so you can use it. In
294 this case, that value is the number of bytes in the user’s input.
295
296 If you don’t call `expect`, the program will compile, but you’ll get a warning:
297
298 ```
299 $ cargo build
300 Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
301 warning: unused `Result` that must be used
302 --> src/main.rs:10:5
303 |
304 10 | io::stdin().read_line(&mut guess);
305 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
306 |
307 = note: `#[warn(unused_must_use)]` on by default
308 = note: this `Result` may be an `Err` variant, which should be handled
309
310 warning: `guessing_game` (bin "guessing_game") generated 1 warning
311 Finished dev [unoptimized + debuginfo] target(s) in 0.59s
312 ```
313
314 <!-- TODO: Update warning output -->
315
316 Rust warns that you haven’t used the `Result` value returned from `read_line`,
317 indicating that the program hasn’t handled a possible error.
318
319 The right way to suppress the warning is to actually write error handling, but
320 in our case we just want to crash this program when a problem occurs, so we can
321 use `expect`. You’ll learn about recovering from errors in Chapter 9.
322
323 ### Printing Values with `println!` Placeholders
324
325 Aside from the closing curly bracket, there’s only one more line to discuss in
326 the code so far:
327
328 ```
329 println!("You guessed: {}", guess);
330 ```
331
332 This line prints the string that now contains the user’s input. The `{}` set of
333 curly brackets is a placeholder: think of `{}` as little crab pincers that hold
334 a value in place. You can print more than one value using curly brackets: the
335 first set of curly brackets holds the first value listed after the format
336 string, the second set holds the second value, and so on. Printing multiple
337 values in one call to `println!` would look like this:
338
339 ```
340 let x = 5;
341 let y = 10;
342
343 println!("x = {} and y = {}", x, y);
344 ```
345
346 This code would print `x = 5 and y = 10`.
347
348 ### Testing the First Part
349
350 Let’s test the first part of the guessing game. Run it using `cargo run`:
351
352 ```
353 $ cargo run
354 Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
355 Finished dev [unoptimized + debuginfo] target(s) in 6.44s
356 Running `target/debug/guessing_game`
357 Guess the number!
358 Please input your guess.
359 6
360 You guessed: 6
361 ```
362
363 At this point, the first part of the game is done: we’re getting input from the
364 keyboard and then printing it.
365
366 ## Generating a Secret Number
367
368 Next, we need to generate a secret number that the user will try to guess. The
369 secret number should be different every time so the game is fun to play more
370 than once. We’ll use a random number between 1 and 100 so the game isn’t too
371 difficult. Rust doesn’t yet include random number functionality in its standard
372 library. However, the Rust team does provide a `rand` crate at
373 *https://crates.io/crates/rand* with said functionality.
374
375 ### Using a Crate to Get More Functionality
376
377 Remember that a crate is a collection of Rust source code files. The project
378 we’ve been building is a *binary crate*, which is an executable. The `rand`
379 crate is a *library crate*, which contains code intended to be used in other
380 programs, and can’t be executed on its own.
381
382 Cargo’s coordination of external crates is where Cargo really shines. Before we
383 can write code that uses `rand`, we need to modify the *Cargo.toml* file to
384 include the `rand` crate as a dependency. Open that file now and add the
385 following line to the bottom beneath the `[dependencies]` section header that
386 Cargo created for you. Be sure to specify `rand` exactly as we have here, with
387 this version number, or the code examples in this tutorial may not work.
388
389 Filename: Cargo.toml
390
391 ```
392 rand = "0.8.3"
393 ```
394
395 In the *Cargo.toml* file, everything that follows a header is part of that
396 section that continues until another section starts. In `[dependencies]` you
397 tell Cargo which external crates your project depends on and which versions of
398 those crates you require. In this case, we specify the `rand` crate with the
399 semantic version specifier `0.8.3`. Cargo understands Semantic Versioning
400 (sometimes called *SemVer*), which is a standard for writing version numbers.
401 The number `0.8.3` is actually shorthand for `^0.8.3`, which means any version
402 that is at least `0.8.3` but below `0.9.0`.
403
404 <!-- As in, it knows not to go outside the 0.8.x range? How does it know to
405 stop at 0.9.0? -->
406 <!-- That's specified in the Semantic Versioning spec and programmed into
407 Cargo. /Carol -->
408
409 Cargo considers these versions to have public APIs compatible with version
410 `0.8.3`, and this specification ensures you’ll get the latest patch release
411 that will still compile with the code in this chapter. Any version `0.9.0` or
412 greater is not guaranteed to have the same API as what the following examples
413 use.
414
415 Now, without changing any of the code, let’s build the project, as shown in
416 Listing 2-2.
417
418 ```
419 $ cargo build
420 Updating crates.io index
421 Downloaded rand v0.8.3
422 Downloaded libc v0.2.86
423 Downloaded getrandom v0.2.2
424 Downloaded cfg-if v1.0.0
425 Downloaded ppv-lite86 v0.2.10
426 Downloaded rand_chacha v0.3.0
427 Downloaded rand_core v0.6.2
428 Compiling rand_core v0.6.2
429 Compiling libc v0.2.86
430 Compiling getrandom v0.2.2
431 Compiling cfg-if v1.0.0
432 Compiling ppv-lite86 v0.2.10
433 Compiling rand_chacha v0.3.0
434 Compiling rand v0.8.3
435 Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
436 Finished dev [unoptimized + debuginfo] target(s) in 2.53s
437 ```
438
439 Listing 2-2: The output from running `cargo build` after adding the rand crate
440 as a dependency
441
442 You may see different version numbers (but they will all be compatible with the
443 code, thanks to SemVer!), different lines (depending on the operating system),
444 and the lines may be in a different order.
445
446 When we include an external dependency, Cargo fetches the latest versions of
447 everything that dependency needs from the *registry*, which is a copy of data
448 from Crates.io at *https://crates.io/*. Crates.io is where people in the Rust
449 ecosystem post their open source Rust projects for others to use.
450
451 After updating the registry, Cargo checks the `[dependencies]` section and
452 downloads any crates listed that aren’t already downloaded. In this case,
453 although we only listed `rand` as a dependency, Cargo also grabbed other crates
454 that `rand` depends on to work. After downloading the crates, Rust compiles
455 them and then compiles the project with the dependencies available.
456
457 If you immediately run `cargo build` again without making any changes, you
458 won’t get any output aside from the `Finished` line. Cargo knows it has already
459 downloaded and compiled the dependencies, and you haven’t changed anything
460 about them in your *Cargo.toml* file. Cargo also knows that you haven’t changed
461 anything about your code, so it doesn’t recompile that either. With nothing to
462 do, it simply exits.
463
464 If you open up the *src/main.rs* file, make a trivial change, and then save it
465 and build again, you’ll only see two lines of output:
466
467 ```
468 $ cargo build
469 Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
470 Finished dev [unoptimized + debuginfo] target(s) in 2.53 secs
471 ```
472
473 These lines show Cargo only updates the build with your tiny change to the
474 *src/main.rs* file. Your dependencies haven’t changed, so Cargo knows it can
475 reuse what it has already downloaded and compiled for those.
476
477 #### Ensuring Reproducible Builds with the *Cargo.lock* File
478
479 Cargo has a mechanism that ensures you can rebuild the same artifact every time
480 you or anyone else builds your code: Cargo will use only the versions of the
481 dependencies you specified until you indicate otherwise. For example, say that
482 next week version 0.8.4 of the `rand` crate comes out, and that version
483 contains an important bug fix, but it also contains a regression that will
484 break your code. To handle this, Rust creates the *Cargo.lock* file the first
485 time you run `cargo build`, so we now have this in the *guessing_game*
486 directory.
487
488 When you build a project for the first time, Cargo figures out all the
489 versions of the dependencies that fit the criteria and then writes them to
490 the *Cargo.lock* file. When you build your project in the future, Cargo will
491 see that the *Cargo.lock* file exists and use the versions specified there
492 rather than doing all the work of figuring out versions again. This lets you
493 have a reproducible build automatically. In other words, your project will
494 remain at `0.8.3` until you explicitly upgrade, thanks to the *Cargo.lock*
495 file.
496
497 #### Updating a Crate to Get a New Version
498
499 When you *do* want to update a crate, Cargo provides the command `update`,
500 which will ignore the *Cargo.lock* file and figure out all the latest versions
501 that fit your specifications in *Cargo.toml*. Cargo will then write those
502 versions to the *Cargo.lock* file. Otherwise, by default, Cargo will only look
503 for versions greater than `0.8.3` and less than `0.9.0`. If the `rand` crate
504 has released the two new versions `0.8.4` and `0.9.0` you would see the
505 following if you ran `cargo update`:
506
507 ```
508 $ cargo update
509 Updating crates.io index
510 Updating rand v0.8.3 -> v0.8.4
511 ```
512
513 Cargo ignores the `0.9.0` releaese. At this point, you would also notice a
514 change in your *Cargo.lock* file noting that the version of the `rand` crate
515 you are now using is `0.8.4`. To use `rand` version `0.9.0` or any version in
516 the `0.9.x` series, you’d have to update the *Cargo.toml* file to look like
517 this instead:
518
519 ```
520 [dependencies]
521 rand = "0.9.0"
522 ```
523
524 The next time you run `cargo build`, Cargo will update the registry of crates
525 available and reevaluate your `rand` requirements according to the new version
526 you have specified.
527
528 There’s a lot more to say about Cargo and its ecosystem which we’ll discuss in
529 Chapter 14, but for now, that’s all you need to know. Cargo makes it very easy
530 to reuse libraries, so Rustaceans are able to write smaller projects that are
531 assembled from a number of packages.
532
533 ### Generating a Random Number
534
535 Let’s start using `rand` to generate a number to guess. The next step is to
536 update *src/main.rs*, as shown in Listing 2-3.
537
538 <!--- It looks like in the last editing we're using the graying out method to
539 highlight the new code here, I'm leaving this note to remind us to implement it
540 when we convert to Word /LC --->
541 <!-- Oh yes, I totally forgot that the print has the graying out, I definitely
542 want to keep that the way it was in the last print version. /Carol -->
543
544 Filename: src/main.rs
545
546 ```
547 use std::io;
548 [1]use rand::Rng;
549
550 fn main() {
551 println!("Guess the number!");
552
553 [2] let secret_number = rand::thread_rng().gen_range(1..101);
554
555 [3] println!("The secret number is: {}", secret_number);
556
557 println!("Please input your guess.");
558
559 let mut guess = String::new();
560
561 io::stdin()
562 .read_line(&mut guess)
563 .expect("Failed to read line");
564
565 println!("You guessed: {}", guess);
566 }
567 ```
568
569 Listing 2-3: Adding code to generate a random number
570
571 <!--- I can't remember how we handled wingdings in markdown before... I don't
572 have those files on this machine. I've just used [x] for now, does that work?
573 Then we'll replace them when we convert to Word /LC --->
574 <!-- I don't think we added the wingdings at all until we moved to Word. For
575 code listings that are the same as the last printing version, I'd definitely
576 like to keep the wingdings the way they were. Using the brackets with numbers
577 as you have here works fine! /Carol -->
578
579 First, we add the line `use rand::Rng` [1]. The `Rng` <!-- TODO: remove range
580 --> trait defines methods that random number generators implement, and this
581 trait must be in scope for us to use those methods. Chapter 10 will cover
582 traits in detail.
583
584 Next, we’re adding two lines in the middle. In the first line [2], we call the
585 `rand::thread_rng` function that gives us the particular random number
586 generator that we’re going to use: one that is local to the current thread of
587 execution and seeded by the operating system. Then we call the `gen_range`
588 method on the random number generator. This method is defined by the `Rng`
589 trait that we brought into scope with the `use rand::Rng` statement. The
590 `gen_range` method takes a range expression as an argument and generates a
591 random number in the range. The kind of range expression we’re using here takes
592 the form `start..end` and is inclusive on the lower bound but exclusive on the
593 upper bound, so we need to specify `1..101` to request a number between 1 and
594 100. Alternatively, we could pass the range `1..=100`, which is equivalent.
595
596 > Note: You won’t just know which traits to use and which methods and functions
597 > to call from a crate, so each crate has documentation with instructions for
598 > using it. Another neat feature of Cargo is that running the `cargo
599 > doc --open` command will build documentation provided by all of your
600 > dependencies locally and open it in your browser. If you’re interested in
601 > other functionality in the `rand` crate, for example, run `cargo doc --open`
602 > and click `rand` in the sidebar on the left.
603
604 The second new line [3] prints the secret number. This is useful while
605 we’re developing the program to be able to test it, but we’ll delete it from
606 the final version. It’s not much of a game if the program prints the answer as
607 soon as it starts!
608
609 Try running the program a few times:
610
611 ```
612 $ cargo run
613 Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
614 Finished dev [unoptimized + debuginfo] target(s) in 2.53s
615 Running `target/debug/guessing_game`
616 Guess the number!
617 The secret number is: 7
618 Please input your guess.
619 4
620 You guessed: 4
621
622 $ cargo run
623 Finished dev [unoptimized + debuginfo] target(s) in 0.02s
624 Running `target/debug/guessing_game`
625 Guess the number!
626 The secret number is: 83
627 Please input your guess.
628 5
629 You guessed: 5
630 ```
631
632 You should get different random numbers, and they should all be numbers between
633 1 and 100. Great job!
634
635 ## Comparing the Guess to the Secret Number
636
637 Now that we have user input and a random number, we can compare them. That step
638 is shown in Listing 2-4. Note that this code won’t compile quite yet, as we
639 will explain.
640
641 Filename: src/main.rs
642
643 ```
644 use rand::Rng;
645 [1]use std::cmp::Ordering;
646 use std::io;
647
648 fn main() {
649 // --snip--
650
651 println!("You guessed: {}", guess);
652
653 match[2] guess.cmp(&secret_number)[3] {
654 Ordering::Less => println!("Too small!"),
655 Ordering::Greater => println!("Too big!"),
656 Ordering::Equal => println!("You win!"),
657 }
658 }
659 ```
660
661 Listing 2-4: Handling the possible return values of comparing two numbers
662
663 First we add another `use` statement [1], bringing a type called
664 `std::cmp::Ordering` into scope from the standard library. The `Ordering` type
665 is another enum and has the variants `Less`, `Greater`, and `Equal`. These are
666 the three outcomes that are possible when you compare two values.
667
668 Then we add five new lines at the bottom that use the `Ordering` type. The
669 `cmp` method [3] compares two values and can be called on anything that can be
670 compared. It takes a reference to whatever you want to compare with: here it’s
671 comparing the `guess` to the `secret_number`. Then it returns a variant of the
672 `Ordering` enum we brought into scope with the `use` statement. We use a
673 `match` expression [2] to decide what to do next based on which variant of
674 `Ordering` was returned from the call to `cmp` with the values in `guess` and
675 `secret_number`.
676
677 A `match` expression is made up of *arms*. An arm consists of a *pattern* to
678 match against, and the code that should be run if the value given to `match`
679 fits that arm’s pattern. Rust takes the value given to `match` and looks
680 through each arm’s pattern in turn. Patterns and the `match` construct are
681 powerful Rust features that let you express a variety of situations your code
682 might encounter and make sure that you handle them all. These features will be
683 covered in detail in Chapter 6 and Chapter 18, respectively.
684
685 Let’s walk through an example with the `match` expression we use here. Say that
686 the user has guessed 50 and the randomly generated secret number this time is
687 38. When the code compares 50 to 38, the `cmp` method will return
688 `Ordering::Greater`, because 50 is greater than 38. The `match` expression gets
689 the `Ordering::Greater` value and starts checking each arm’s pattern. It looks
690 at the first arm’s pattern, `Ordering::Less`, and sees that the value
691 `Ordering::Greater` does not match `Ordering::Less`, so it ignores the code in
692 that arm and moves to the next arm. The next arm’s pattern is
693 `Ordering::Greater`, which *does* match `Ordering::Greater`! The associated
694 code in that arm will execute and print `Too big!` to the screen. The `match`
695 expression ends because it has no need to look at the last arm in this scenario.
696
697 However, the code in Listing 2-4 won’t compile yet. Let’s try it:
698
699 ```
700 $ cargo build
701 Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
702 error[E0308]: mismatched types
703 --> src/main.rs:22:21
704 |
705 22 | match guess.cmp(&secret_number) {
706 | ^^^^^^^^^^^^^^ expected struct `String`, found integer
707 |
708 = note: expected reference `&String`
709 found reference `&{integer}`
710 ```
711
712 The core of the error states that there are *mismatched types*. Rust has a
713 strong, static type system. However, it also has type inference. When we wrote
714 `let mut guess = String::new()`, Rust was able to infer that `guess` should be
715 a `String` and didn’t make us write the type. The `secret_number`, on the other
716 hand, is a number type. A few of Rust’s number types can have a value between 1
717 and 100: `i32`, a 32-bit number; `u32`, an unsigned 32-bit number; `i64`, a
718 64-bit number; as well as others. Unless otherwise speceified, Rust defaults to
719 an `i32`, which is the type of `secret_number` unless you add type information
720 elsewhere that would cause Rust to infer a different numerical type. The reason
721 for the error is that Rust cannot compare a string and a number type.
722
723 Ultimately, we want to convert the `String` the program reads as input into a
724 real number type so we can compare it numerically to the secret number. We do so
725 by adding this line to the `main` function body:
726
727 Filename: src/main.rs
728
729 ```
730 // --snip--
731
732 let mut guess = String::new();
733
734 io::stdin()
735 .read_line(&mut guess)
736 .expect("Failed to read line");
737
738 let guess: u32 = guess.trim().parse().expect("Please type a number!");
739
740 println!("You guessed: {}", guess);
741
742 match guess.cmp(&secret_number) {
743 Ordering::Less => println!("Too small!"),
744 Ordering::Greater => println!("Too big!"),
745 Ordering::Equal => println!("You win!"),
746 }
747 ```
748
749 We create a variable named `guess`. But wait, doesn’t the program already have
750 a variable named `guess`? It does, but helpfully Rust allows us to *shadow* the
751 previous value of `guess` with a new one. Shadowing lets us reuse the `guess`
752 variable name rather than forcing us to create two unique variables, such as
753 `guess_str` and `guess` for example. We’ll cover this in more detail in Chapter
754 3, but for now know that this feature is often used when you want to convert a
755 value from one type to another type.
756
757 We bind this new variable to the expression `guess.trim().parse()`. The `guess`
758 in the expression refers to the original `guess` variable that contained the
759 input as a string. The `trim` method on a `String` instance will eliminate any
760 whitespace at the beginning and end, which we must do to be able to compare the
761 string to the `u32`, which can only contain numerical data. <!--- do we
762 eliminate the whitespace to allows us to compare it to the number accurately?
763 I've assumed so, but please check my wording here /LC -->
764 <!-- Yep, the wording here seems fine! /Carol -->
765 The user must press <span class="keystroke">enter</span> to satisfy `read_line`
766 and input their guess, which adds a newline character to the string. For
767 example, if the user types <span class="keystroke">5</span> and presses <span
768 class="keystroke">enter</span>, `guess` looks like this: `5\n`. The `\n`
769 represents “newline”. (On Windows, pressing <span
770 class="keystroke">enter</span> results in a carriage return and a newline,
771 `\r\n`). The `trim` method eliminates `\n` or `\r\n`, resulting in just `5`.
772
773 The `parse` method on strings parses a string into some kind of number. Because
774 this method can parse a variety of number types, we need to tell Rust the exact
775 number type we want by using `let guess: u32`. The colon (`:`) after `guess`
776 tells Rust we’ll annotate the variable’s type. Rust has a few built-in number
777 types; the `u32` seen here is an unsigned, 32-bit integer. It’s a good default
778 choice for a small positive number. You’ll learn about other number types in
779 Chapter 3. Additionally, the `u32` annotation in this example program and the
780 comparison with `secret_number` means that Rust will infer that `secret_number`
781 should be a `u32` as well. So now the comparison will be between two values of
782 the same type!
783
784 The `parse` method will only work on characters that can logically be converted
785 into numbers and so can easily cause errors. If, for example, the string
786 contained `A👍%`, there would be no way to convert that to a number. Because it
787 might fail, the `parse` method returns a `Result` type, much as the `read_line`
788 method does (discussed earlier in “Handling Potential Failure with the `Result`
789 Type”). We’ll treat this `Result` the same way by using the `expect` method
790 again. If `parse` returns an `Err` `Result` variant because it couldn’t create
791 a number from the string, the `expect` call will crash the game and print the
792 message we give it. If `parse` can successfully convert the string to a number,
793 it will return the `Ok` variant of `Result`, and `expect` will return the
794 number that we want from the `Ok` value.
795
796 Let’s run the program now!
797
798 ```
799 $ cargo run
800 Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
801 Finished dev [unoptimized + debuginfo] target(s) in 0.43s
802 Running `target/debug/guessing_game`
803 Guess the number!
804 The secret number is: 58
805 Please input your guess.
806 76
807 You guessed: 76
808 Too big!
809 ```
810
811 Nice! Even though spaces were added before the guess, the program still figured
812 out that the user guessed 76. Run the program a few times to verify the
813 different behavior with different kinds of input: guess the number correctly,
814 guess a number that is too high, and guess a number that is too low.
815
816 We have most of the game working now, but the user can make only one guess.
817 Let’s change that by adding a loop!
818
819 ## Allowing Multiple Guesses with Looping
820
821 The `loop` keyword creates an infinite loop. We’ll add a loop to give users
822 more chances at guessing the number:
823
824 Filename: src/main.rs
825
826 ```
827 // --snip--
828
829 println!("The secret number is: {}", secret_number);
830
831 loop {
832 println!("Please input your guess.");
833
834 // --snip--
835
836 match guess.cmp(&secret_number) {
837 Ordering::Less => println!("Too small!"),
838 Ordering::Greater => println!("Too big!"),
839 Ordering::Equal => println!("You win!"),
840 }
841 }
842 }
843 ```
844
845 As you can see, we’ve moved everything from the guess input prompt onward into
846 a loop. Be sure to indent the lines inside the loop another four spaces each
847 and run the program again. The program will now ask for another guess forever,
848 which actually introduces a new problem. It doesn’t seem like the user can quit!
849
850 The user could always interrupt the program by using the keyboard shortcut
851 <span class="keystroke">ctrl-c</span>. But there’s another way to escape this
852 insatiable monster, as mentioned in the `parse` discussion in “Comparing the
853 Guess to the Secret Number”: if the user enters a non-number answer, the
854 program will crash. We can take advantage of that to allow the user to quit, as
855 shown here:
856
857 ```
858 $ cargo run
859 Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
860 Finished dev [unoptimized + debuginfo] target(s) in 1.50s
861 Running `target/debug/guessing_game`
862 Guess the number!
863 The secret number is: 59
864 Please input your guess.
865 45
866 You guessed: 45
867 Too small!
868 Please input your guess.
869 60
870 You guessed: 60
871 Too big!
872 Please input your guess.
873 59
874 You guessed: 59
875 You win!
876 Please input your guess.
877 quit
878 thread 'main' panicked at 'Please type a number!: ParseIntError { kind: InvalidDigit }', src/main.rs:28:47
879 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
880 ```
881
882 Typing `quit` will quit the game, but as you’ll notice so will entering any
883 other non-number input. This is suboptimal to say the least; we want the game
884 to also stop when the correct number is guessed.
885
886 ### Quitting After a Correct Guess
887
888 Let’s program the game to quit when the user wins by adding a `break` statement:
889
890 Filename: src/main.rs
891
892 ```
893 // --snip--
894
895 match guess.cmp(&secret_number) {
896 Ordering::Less => println!("Too small!"),
897 Ordering::Greater => println!("Too big!"),
898 Ordering::Equal => {
899 println!("You win!");
900 break;
901 }
902 }
903 }
904 }
905 ```
906
907 Adding the `break` line after `You win!` makes the program exit the loop when
908 the user guesses the secret number correctly. Exiting the loop also means
909 exiting the program, because the loop is the last part of `main`.
910
911 ### Handling Invalid Input
912
913 To further refine the game’s behavior, rather than crashing the program when
914 the user inputs a non-number, let’s make the game ignore a non-number so the
915 user can continue guessing. We can do that by altering the line where `guess`
916 is converted from a `String` to a `u32`, as shown in Listing 2-5.
917
918 Filename: src/main.rs
919
920 ```
921 // --snip--
922
923 io::stdin()
924 .read_line(&mut guess)
925 .expect("Failed to read line");
926
927 let guess: u32 = match guess.trim().parse() {
928 Ok(num) => num,
929 Err(_) => continue,
930 };
931
932 println!("You guessed: {}", guess);
933
934 // --snip--
935 ```
936
937 Listing 2-5: Ignoring a non-number guess and asking for another guess instead
938 of crashing the program
939
940 We switch from an `expect` call to a `match` expression to move from crashing
941 on an error to handling the error. Remember that `parse` returns a `Result`
942 type and `Result` is an enum that has the variants `Ok` or `Err`. We’re using a
943 `match` expression here, as we did with the `Ordering` result of the `cmp`
944 method.
945
946 If `parse` is able to successfully turn the string into a number, it will
947 return an `Ok` value that contains the resulting number. That `Ok` value will
948 match the first arm’s pattern, and the `match` expression will just return the
949 `num` value that `parse` produced and put inside the `Ok` value. That number
950 will end up right where we want it in the new `guess` variable we’re creating.
951
952 If `parse` is *not* able to turn the string into a number, it will return an
953 `Err` value that contains more information about the error. The `Err` value
954 does not match the `Ok(num)` pattern in the first `match` arm, but it does
955 match the `Err(_)` pattern in the second arm. The underscore, `_`, is a
956 catchall value; in this example, we’re saying we want to match all `Err`
957 values, no matter what information they have inside them. So the program will
958 execute the second arm’s code, `continue`, which tells the program to go to the
959 next iteration of the `loop` and ask for another guess. So, effectively, the
960 program ignores all errors that `parse` might encounter!
961
962 Now everything in the program should work as expected. Let’s try it:
963
964 ```
965 $ cargo run
966 Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
967 Finished dev [unoptimized + debuginfo] target(s) in 4.45s
968 Running `target/debug/guessing_game`
969 Guess the number!
970 The secret number is: 61
971 Please input your guess.
972 10
973 You guessed: 10
974 Too small!
975 Please input your guess.
976 99
977 You guessed: 99
978 Too big!
979 Please input your guess.
980 foo
981 Please input your guess.
982 61
983 You guessed: 61
984 You win!
985 ```
986
987 Awesome! With one tiny final tweak, we will finish the guessing game. Recall
988 that the program is still printing the secret number. That worked well for
989 testing, but it ruins the game. Let’s delete the `println!` that outputs the
990 secret number. Listing 2-6 shows the final code.
991
992 Filename: src/main.rs
993
994 ```
995 use rand::Rng;
996 use std::cmp::Ordering;
997 use std::io;
998
999 fn main() {
1000 println!("Guess the number!");
1001
1002 let secret_number = rand::thread_rng().gen_range(1..101);
1003
1004 loop {
1005 println!("Please input your guess.");
1006
1007 let mut guess = String::new();
1008
1009 io::stdin()
1010 .read_line(&mut guess)
1011 .expect("Failed to read line");
1012
1013 let guess: u32 = match guess.trim().parse() {
1014 Ok(num) => num,
1015 Err(_) => continue,
1016 };
1017
1018 println!("You guessed: {}", guess);
1019
1020 match guess.cmp(&secret_number) {
1021 Ordering::Less => println!("Too small!"),
1022 Ordering::Greater => println!("Too big!"),
1023 Ordering::Equal => {
1024 println!("You win!");
1025 break;
1026 }
1027 }
1028 }
1029 }
1030 ```
1031
1032 Listing 2-6: Complete guessing game code
1033
1034 ## Summary
1035
1036 At this point, you’ve successfully built the guessing game. Congratulations!
1037
1038 This project was a hands-on way to introduce you to many new Rust concepts:
1039 `let`, `match`, functions, the use of external crates, and more. In the next
1040 few chapters, you’ll learn about these concepts in more detail. Chapter 3
1041 covers concepts that most programming languages have, such as variables, data
1042 types, and functions, and shows how to use them in Rust. Chapter 4 explores
1043 ownership, a feature that makes Rust different from other languages. Chapter 5
1044 discusses structs and method syntax, and Chapter 6 explains how enums work.