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