]> git.proxmox.com Git - rustc.git/blame - src/doc/trpl/guessing-game.md
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / doc / trpl / guessing-game.md
CommitLineData
bd371182
AL
1% Guessing Game
2
3For our first project, we’ll implement a classic beginner programming problem:
4the guessing game. Here’s how it works: Our program will generate a random
5integer between one and a hundred. It will then prompt us to enter a guess.
6Upon entering our guess, it will tell us if we’re too low or too high. Once we
7guess correctly, it will congratulate us. Sounds good?
8
9# Set up
10
11Let’s set up a new project. Go to your projects directory. Remember how we had
12to create our directory structure and a `Cargo.toml` for `hello_world`? Cargo
13has a command that does that for us. Let’s give it a shot:
14
15```bash
16$ cd ~/projects
17$ cargo new guessing_game --bin
18$ cd guessing_game
19```
20
21We pass the name of our project to `cargo new`, and then the `--bin` flag,
22since we’re making a binary, rather than a library.
23
24Check out the generated `Cargo.toml`:
25
26```toml
27[package]
28
29name = "guessing_game"
d9579d0f 30version = "0.1.0"
bd371182
AL
31authors = ["Your Name <you@example.com>"]
32```
33
34Cargo gets this information from your environment. If it’s not correct, go ahead
35and fix that.
36
37Finally, Cargo generated a ‘Hello, world!’ for us. Check out `src/main.rs`:
38
39```rust
40fn main() {
62682a34 41 println!("Hello, world!");
bd371182
AL
42}
43```
44
45Let’s try compiling what Cargo gave us:
46
47```{bash}
48$ cargo build
d9579d0f 49 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
bd371182
AL
50```
51
52Excellent! Open up your `src/main.rs` again. We’ll be writing all of
53our code in this file.
54
55Before we move on, let me show you one more Cargo command: `run`. `cargo run`
56is kind of like `cargo build`, but it also then runs the produced executable.
57Try it out:
58
59```bash
60$ cargo run
d9579d0f 61 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
bd371182
AL
62 Running `target/debug/guessing_game`
63Hello, world!
64```
65
66Great! The `run` command comes in handy when you need to rapidly iterate on a
67project. Our game is just such a project, we need to quickly test each
68iteration before moving on to the next one.
69
70# Processing a Guess
71
72Let’s get to it! The first thing we need to do for our guessing game is
73allow our player to input a guess. Put this in your `src/main.rs`:
74
75```rust,no_run
76use std::io;
77
78fn main() {
79 println!("Guess the number!");
80
81 println!("Please input your guess.");
82
83 let mut guess = String::new();
84
85 io::stdin().read_line(&mut guess)
86 .ok()
87 .expect("Failed to read line");
88
89 println!("You guessed: {}", guess);
90}
91```
92
93There’s a lot here! Let’s go over it, bit by bit.
94
95```rust,ignore
96use std::io;
97```
98
99We’ll need to take user input, and then print the result as output. As such, we
100need the `io` library from the standard library. Rust only imports a few things
c1a9b12d
SL
101by default into every program, [the ‘prelude’][prelude]. If it’s not in the
102prelude, you’ll have to `use` it directly.
bd371182
AL
103
104[prelude]: ../std/prelude/index.html
105
106```rust,ignore
107fn main() {
108```
109
110As you’ve seen before, the `main()` function is the entry point into your
111program. The `fn` syntax declares a new function, the `()`s indicate that
112there are no arguments, and `{` starts the body of the function. Because
113we didn’t include a return type, it’s assumed to be `()`, an empty
114[tuple][tuples].
115
116[tuples]: primitive-types.html#tuples
117
118```rust,ignore
119 println!("Guess the number!");
120
121 println!("Please input your guess.");
122```
123
124We previously learned that `println!()` is a [macro][macros] that
125prints a [string][strings] to the screen.
126
127[macros]: macros.html
128[strings]: strings.html
129
130```rust,ignore
131 let mut guess = String::new();
132```
133
134Now we’re getting interesting! There’s a lot going on in this little line.
135The first thing to notice is that this is a [let statement][let], which is
136used to create ‘variable bindings’. They take this form:
137
138```rust,ignore
139let foo = bar;
140```
141
142[let]: variable-bindings.html
143
144This will create a new binding named `foo`, and bind it to the value `bar`. In
145many languages, this is called a ‘variable’, but Rust’s variable bindings have
146a few tricks up their sleeves.
147
148For example, they’re [immutable][immutable] by default. That’s why our example
149uses `mut`: it makes a binding mutable, rather than immutable. `let` doesn’t
150take a name on the left hand side, it actually accepts a
62682a34 151‘[pattern][patterns]’. We’ll use patterns later. It’s easy enough
bd371182
AL
152to use for now:
153
62682a34 154```rust
bd371182
AL
155let foo = 5; // immutable.
156let mut bar = 5; // mutable
157```
158
159[immutable]: mutability.html
160[patterns]: patterns.html
161
162Oh, and `//` will start a comment, until the end of the line. Rust ignores
163everything in [comments][comments].
164
165[comments]: comments.html
166
167So now we know that `let mut guess` will introduce a mutable binding named
168`guess`, but we have to look at the other side of the `=` for what it’s
169bound to: `String::new()`.
170
171`String` is a string type, provided by the standard library. A
172[`String`][string] is a growable, UTF-8 encoded bit of text.
173
174[string]: ../std/string/struct.String.html
175
176The `::new()` syntax uses `::` because this is an ‘associated function’ of
177a particular type. That is to say, it’s associated with `String` itself,
178rather than a particular instance of a `String`. Some languages call this a
179‘static method’.
180
181This function is named `new()`, because it creates a new, empty `String`.
182You’ll find a `new()` function on many types, as it’s a common name for making
183a new value of some kind.
184
185Let’s move forward:
186
187```rust,ignore
188 io::stdin().read_line(&mut guess)
189 .ok()
190 .expect("Failed to read line");
191```
192
193That’s a lot more! Let’s go bit-by-bit. The first line has two parts. Here’s
194the first:
195
196```rust,ignore
197io::stdin()
198```
199
200Remember how we `use`d `std::io` on the first line of the program? We’re now
201calling an associated function on it. If we didn’t `use std::io`, we could
202have written this line as `std::io::stdin()`.
203
204This particular function returns a handle to the standard input for your
205terminal. More specifically, a [std::io::Stdin][iostdin].
206
207[iostdin]: ../std/io/struct.Stdin.html
208
209The next part will use this handle to get input from the user:
210
211```rust,ignore
212.read_line(&mut guess)
213```
214
215Here, we call the [`read_line()`][read_line] method on our handle.
d9579d0f 216[Methods][method] are like associated functions, but are only available on a
bd371182
AL
217particular instance of a type, rather than the type itself. We’re also passing
218one argument to `read_line()`: `&mut guess`.
219
220[read_line]: ../std/io/struct.Stdin.html#method.read_line
d9579d0f 221[method]: method-syntax.html
bd371182
AL
222
223Remember how we bound `guess` above? We said it was mutable. However,
224`read_line` doesn’t take a `String` as an argument: it takes a `&mut String`.
225Rust has a feature called ‘[references][references]’, which allows you to have
226multiple references to one piece of data, which can reduce copying. References
227are a complex feature, as one of Rust’s major selling points is how safe and
228easy it is to use references. We don’t need to know a lot of those details to
229finish our program right now, though. For now, all we need to know is that
230like `let` bindings, references are immutable by default. Hence, we need to
231write `&mut guess`, rather than `&guess`.
232
233Why does `read_line()` take a mutable reference to a string? Its job is
234to take what the user types into standard input, and place that into a
235string. So it takes that string as an argument, and in order to add
236the input, it needs to be mutable.
237
238[references]: references-and-borrowing.html
239
240But we’re not quite done with this line of code, though. While it’s
241a single line of text, it’s only the first part of the single logical line of
242code:
243
244```rust,ignore
245 .ok()
246 .expect("Failed to read line");
247```
248
249When you call a method with the `.foo()` syntax, you may introduce a newline
250and other whitespace. This helps you split up long lines. We _could_ have
251done:
252
253```rust,ignore
254 io::stdin().read_line(&mut guess).ok().expect("failed to read line");
255```
256
257But that gets hard to read. So we’ve split it up, three lines for three
258method calls. We already talked about `read_line()`, but what about `ok()`
259and `expect()`? Well, we already mentioned that `read_line()` puts what
260the user types into the `&mut String` we pass it. But it also returns
261a value: in this case, an [`io::Result`][ioresult]. Rust has a number of
262types named `Result` in its standard library: a generic [`Result`][result],
263and then specific versions for sub-libraries, like `io::Result`.
264
265[ioresult]: ../std/io/type.Result.html
266[result]: ../std/result/enum.Result.html
267
268The purpose of these `Result` types is to encode error handling information.
269Values of the `Result` type, like any type, have methods defined on them. In
270this case, `io::Result` has an `ok()` method, which says ‘we want to assume
271this value is a successful one. If not, just throw away the error
272information’. Why throw it away? Well, for a basic program, we just want to
273print a generic error, as basically any issue means we can’t continue. The
274[`ok()` method][ok] returns a value which has another method defined on it:
275`expect()`. The [`expect()` method][expect] takes a value it’s called on, and
276if it isn’t a successful one, [`panic!`][panic]s with a message you
277passed it. A `panic!` like this will cause our program to crash, displaying
278the message.
279
280[ok]: ../std/result/enum.Result.html#method.ok
281[expect]: ../std/option/enum.Option.html#method.expect
282[panic]: error-handling.html
283
284If we leave off calling these two methods, our program will compile, but
285we’ll get a warning:
286
287```bash
288$ cargo build
289 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
290src/main.rs:10:5: 10:39 warning: unused result which must be used,
291#[warn(unused_must_use)] on by default
292src/main.rs:10 io::stdin().read_line(&mut guess);
293 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
294```
295
296Rust warns us that we haven’t used the `Result` value. This warning comes from
297a special annotation that `io::Result` has. Rust is trying to tell you that
298you haven’t handled a possible error. The right way to suppress the error is
299to actually write error handling. Luckily, if we just want to crash if there’s
300a problem, we can use these two little methods. If we can recover from the
301error somehow, we’d do something else, but we’ll save that for a future
302project.
303
304There’s just one line of this first example left:
305
306```rust,ignore
307 println!("You guessed: {}", guess);
308}
309```
310
311This prints out the string we saved our input in. The `{}`s are a placeholder,
312and so we pass it `guess` as an argument. If we had multiple `{}`s, we would
313pass multiple arguments:
314
315```rust
316let x = 5;
317let y = 10;
318
319println!("x and y: {} and {}", x, y);
320```
321
322Easy.
323
324Anyway, that’s the tour. We can run what we have with `cargo run`:
325
326```bash
327$ cargo run
328 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
329 Running `target/debug/guessing_game`
330Guess the number!
331Please input your guess.
3326
333You guessed: 6
334```
335
336All right! Our first part is done: we can get input from the keyboard,
337and then print it back out.
338
339# Generating a secret number
340
341Next, we need to generate a secret number. Rust does not yet include random
342number functionality in its standard library. The Rust team does, however,
343provide a [`rand` crate][randcrate]. A ‘crate’ is a package of Rust code.
344We’ve been building a ‘binary crate’, which is an executable. `rand` is a
345‘library crate’, which contains code that’s intended to be used with other
346programs.
347
348[randcrate]: https://crates.io/crates/rand
349
350Using external crates is where Cargo really shines. Before we can write
351the code using `rand`, we need to modify our `Cargo.toml`. Open it up, and
352add these few lines at the bottom:
353
354```toml
355[dependencies]
356
357rand="0.3.0"
358```
359
360The `[dependencies]` section of `Cargo.toml` is like the `[package]` section:
361everything that follows it is part of it, until the next section starts.
362Cargo uses the dependencies section to know what dependencies on external
c1a9b12d
SL
363crates you have, and what versions you require. In this case, we’ve specified version `0.3.0`,
364which Cargo understands to be any release that’s compatible with this specific version.
bd371182 365Cargo understands [Semantic Versioning][semver], which is a standard for writing version
c1a9b12d
SL
366numbers. If we wanted to use only `0.3.0` exactly, we could use `=0.3.0`. If we
367wanted to use the latest version we could use `*`; We could use a range of
368versions. [Cargo’s documentation][cargodoc] contains more details.
bd371182
AL
369
370[semver]: http://semver.org
371[cargodoc]: http://doc.crates.io/crates-io.html
372
373Now, without changing any of our code, let’s build our project:
374
375```bash
376$ cargo build
377 Updating registry `https://github.com/rust-lang/crates.io-index`
378 Downloading rand v0.3.8
379 Downloading libc v0.1.6
380 Compiling libc v0.1.6
381 Compiling rand v0.3.8
382 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
383```
384
385(You may see different versions, of course.)
386
387Lots of new output! Now that we have an external dependency, Cargo fetches the
388latest versions of everything from the registry, which is a copy of data from
389[Crates.io][cratesio]. Crates.io is where people in the Rust ecosystem
390post their open source Rust projects for others to use.
391
392[cratesio]: https://crates.io
393
394After updating the registry, Cargo checks our `[dependencies]` and downloads
395any we don’t have yet. In this case, while we only said we wanted to depend on
396`rand`, we’ve also grabbed a copy of `libc`. This is because `rand` depends on
397`libc` to work. After downloading them, it compiles them, and then compiles
398our project.
399
400If we run `cargo build` again, we’ll get different output:
401
402```bash
403$ cargo build
404```
405
406That’s right, no output! Cargo knows that our project has been built, and that
407all of its dependencies are built, and so there’s no reason to do all that
408stuff. With nothing to do, it simply exits. If we open up `src/main.rs` again,
409make a trivial change, and then save it again, we’ll just see one line:
410
411```bash
412$ cargo build
413 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
414```
415
416So, we told Cargo we wanted any `0.3.x` version of `rand`, and so it fetched the latest
417version at the time this was written, `v0.3.8`. But what happens when next
418week, version `v0.3.9` comes out, with an important bugfix? While getting
419bugfixes is important, what if `0.3.9` contains a regression that breaks our
420code?
421
422The answer to this problem is the `Cargo.lock` file you’ll now find in your
423project directory. When you build your project for the first time, Cargo
424figures out all of the versions that fit your criteria, and then writes them
425to the `Cargo.lock` file. When you build your project in the future, Cargo
426will see that the `Cargo.lock` file exists, and then use that specific version
427rather than do all the work of figuring out versions again. This lets you
428have a repeatable build automatically. In other words, we’ll stay at `0.3.8`
429until we explicitly upgrade, and so will anyone who we share our code with,
430thanks to the lock file.
431
432What about when we _do_ want to use `v0.3.9`? Cargo has another command,
433`update`, which says ‘ignore the lock, figure out all the latest versions that
434fit what we’ve specified. If that works, write those versions out to the lock
435file’. But, by default, Cargo will only look for versions larger than `0.3.0`
436and smaller than `0.4.0`. If we want to move to `0.4.x`, we’d have to update
437the `Cargo.toml` directly. When we do, the next time we `cargo build`, Cargo
438will update the index and re-evaluate our `rand` requirements.
439
440There’s a lot more to say about [Cargo][doccargo] and [its
441ecosystem][doccratesio], but for now, that’s all we need to know. Cargo makes
442it really easy to re-use libraries, and so Rustaceans tend to write smaller
443projects which are assembled out of a number of sub-packages.
444
445[doccargo]: http://doc.crates.io
446[doccratesio]: http://doc.crates.io/crates-io.html
447
448Let’s get on to actually _using_ `rand`. Here’s our next step:
449
450```rust,ignore
451extern crate rand;
452
453use std::io;
454use rand::Rng;
455
456fn main() {
457 println!("Guess the number!");
458
459 let secret_number = rand::thread_rng().gen_range(1, 101);
460
461 println!("The secret number is: {}", secret_number);
462
463 println!("Please input your guess.");
464
465 let mut guess = String::new();
466
467 io::stdin().read_line(&mut guess)
468 .ok()
469 .expect("failed to read line");
470
471 println!("You guessed: {}", guess);
472}
473```
474
475The first thing we’ve done is change the first line. It now says
476`extern crate rand`. Because we declared `rand` in our `[dependencies]`, we
477can use `extern crate` to let Rust know we’ll be making use of it. This also
478does the equivalent of a `use rand;` as well, so we can make use of anything
479in the `rand` crate by prefixing it with `rand::`.
480
481Next, we added another `use` line: `use rand::Rng`. We’re going to use a
482method in a moment, and it requires that `Rng` be in scope to work. The basic
483idea is this: methods are defined on something called ‘traits’, and for the
484method to work, it needs the trait to be in scope. For more about the
485details, read the [traits][traits] section.
486
487[traits]: traits.html
488
489There are two other lines we added, in the middle:
490
491```rust,ignore
492 let secret_number = rand::thread_rng().gen_range(1, 101);
493
494 println!("The secret number is: {}", secret_number);
495```
496
497We use the `rand::thread_rng()` function to get a copy of the random number
498generator, which is local to the particular [thread][concurrency] of execution
499we’re in. Because we `use rand::Rng`’d above, it has a `gen_range()` method
500available. This method takes two arguments, and generates a number between
501them. It’s inclusive on the lower bound, but exclusive on the upper bound,
c1a9b12d 502so we need `1` and `101` to get a number ranging from one to a hundred.
bd371182
AL
503
504[concurrency]: concurrency.html
505
506The second line just prints out the secret number. This is useful while
507we’re developing our program, so we can easily test it out. But we’ll be
508deleting it for the final version. It’s not much of a game if it prints out
509the answer when you start it up!
510
511Try running our new program a few times:
512
513```bash
514$ cargo run
515 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
516 Running `target/debug/guessing_game`
517Guess the number!
518The secret number is: 7
519Please input your guess.
5204
521You guessed: 4
522$ cargo run
523 Running `target/debug/guessing_game`
524Guess the number!
525The secret number is: 83
526Please input your guess.
5275
528You guessed: 5
529```
530
531Great! Next up: let’s compare our guess to the secret guess.
532
533# Comparing guesses
534
535Now that we’ve got user input, let’s compare our guess to the random guess.
536Here’s our next step, though it doesn’t quite work yet:
537
538```rust,ignore
539extern crate rand;
540
541use std::io;
542use std::cmp::Ordering;
543use rand::Rng;
544
545fn main() {
546 println!("Guess the number!");
547
548 let secret_number = rand::thread_rng().gen_range(1, 101);
549
550 println!("The secret number is: {}", secret_number);
551
552 println!("Please input your guess.");
553
554 let mut guess = String::new();
555
556 io::stdin().read_line(&mut guess)
557 .ok()
558 .expect("failed to read line");
559
560 println!("You guessed: {}", guess);
561
562 match guess.cmp(&secret_number) {
563 Ordering::Less => println!("Too small!"),
564 Ordering::Greater => println!("Too big!"),
565 Ordering::Equal => println!("You win!"),
566 }
567}
568```
569
570A few new bits here. The first is another `use`. We bring a type called
571`std::cmp::Ordering` into scope. Then, five new lines at the bottom that use
572it:
573
574```rust,ignore
575match guess.cmp(&secret_number) {
576 Ordering::Less => println!("Too small!"),
577 Ordering::Greater => println!("Too big!"),
578 Ordering::Equal => println!("You win!"),
579}
580```
581
582The `cmp()` method can be called on anything that can be compared, and it
583takes a reference to the thing you want to compare it to. It returns the
584`Ordering` type we `use`d earlier. We use a [`match`][match] statement to
585determine exactly what kind of `Ordering` it is. `Ordering` is an
586[`enum`][enum], short for ‘enumeration’, which looks like this:
587
588```rust
589enum Foo {
590 Bar,
591 Baz,
592}
593```
594
595[match]: match.html
596[enum]: enums.html
597
598With this definition, anything of type `Foo` can be either a
599`Foo::Bar` or a `Foo::Baz`. We use the `::` to indicate the
600namespace for a particular `enum` variant.
601
602The [`Ordering`][ordering] enum has three possible variants: `Less`, `Equal`,
603and `Greater`. The `match` statement takes a value of a type, and lets you
604create an ‘arm’ for each possible value. Since we have three types of
605`Ordering`, we have three arms:
606
607```rust,ignore
608match guess.cmp(&secret_number) {
609 Ordering::Less => println!("Too small!"),
610 Ordering::Greater => println!("Too big!"),
611 Ordering::Equal => println!("You win!"),
612}
613```
614
615[ordering]: ../std/cmp/enum.Ordering.html
616
617If it’s `Less`, we print `Too small!`, if it’s `Greater`, `Too big!`, and if
618`Equal`, `You win!`. `match` is really useful, and is used often in Rust.
619
620I did mention that this won’t quite work yet, though. Let’s try it:
621
622```bash
623$ cargo build
624 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
625src/main.rs:28:21: 28:35 error: mismatched types:
626 expected `&collections::string::String`,
627 found `&_`
628(expected struct `collections::string::String`,
629 found integral variable) [E0308]
630src/main.rs:28 match guess.cmp(&secret_number) {
631 ^~~~~~~~~~~~~~
632error: aborting due to previous error
633Could not compile `guessing_game`.
634```
635
636Whew! This is a big error. The core of it is that we have ‘mismatched types’.
637Rust has a strong, static type system. However, it also has type inference.
638When we wrote `let guess = String::new()`, Rust was able to infer that `guess`
639should be a `String`, and so it doesn’t make us write out the type. And with
640our `secret_number`, there are a number of types which can have a value
641between one and a hundred: `i32`, a thirty-two-bit number, or `u32`, an
62682a34 642unsigned thirty-two-bit number, or `i64`, a sixty-four-bit number or others.
bd371182
AL
643So far, that hasn’t mattered, and so Rust defaults to an `i32`. However, here,
644Rust doesn’t know how to compare the `guess` and the `secret_number`. They
645need to be the same type. Ultimately, we want to convert the `String` we
646read as input into a real number type, for comparison. We can do that
647with three more lines. Here’s our new program:
648
649```rust,ignore
650extern crate rand;
651
652use std::io;
653use std::cmp::Ordering;
654use rand::Rng;
655
656fn main() {
657 println!("Guess the number!");
658
659 let secret_number = rand::thread_rng().gen_range(1, 101);
660
661 println!("The secret number is: {}", secret_number);
662
663 println!("Please input your guess.");
664
665 let mut guess = String::new();
666
667 io::stdin().read_line(&mut guess)
668 .ok()
669 .expect("failed to read line");
670
671 let guess: u32 = guess.trim().parse()
672 .ok()
673 .expect("Please type a number!");
674
675 println!("You guessed: {}", guess);
676
677 match guess.cmp(&secret_number) {
678 Ordering::Less => println!("Too small!"),
679 Ordering::Greater => println!("Too big!"),
680 Ordering::Equal => println!("You win!"),
681 }
682}
683```
684
685The new three lines:
686
687```rust,ignore
688 let guess: u32 = guess.trim().parse()
689 .ok()
690 .expect("Please type a number!");
691```
692
693Wait a minute, I thought we already had a `guess`? We do, but Rust allows us
694to ‘shadow’ the previous `guess` with a new one. This is often used in this
695exact situation, where `guess` starts as a `String`, but we want to convert it
696to an `u32`. Shadowing lets us re-use the `guess` name, rather than forcing us
697to come up with two unique names like `guess_str` and `guess`, or something
698else.
699
700We bind `guess` to an expression that looks like something we wrote earlier:
701
702```rust,ignore
703guess.trim().parse()
704```
705
706Followed by an `ok().expect()` invocation. Here, `guess` refers to the old
707`guess`, the one that was a `String` with our input in it. The `trim()`
708method on `String`s will eliminate any white space at the beginning and end of
709our string. This is important, as we had to press the ‘return’ key to satisfy
710`read_line()`. This means that if we type `5` and hit return, `guess` looks
711like this: `5\n`. The `\n` represents ‘newline’, the enter key. `trim()` gets
712rid of this, leaving our string with just the `5`. The [`parse()` method on
713strings][parse] parses a string into some kind of number. Since it can parse a
714variety of numbers, we need to give Rust a hint as to the exact type of number
715we want. Hence, `let guess: u32`. The colon (`:`) after `guess` tells Rust
716we’re going to annotate its type. `u32` is an unsigned, thirty-two bit
717integer. Rust has [a number of built-in number types][number], but we’ve
718chosen `u32`. It’s a good default choice for a small positive number.
719
720[parse]: ../std/primitive.str.html#method.parse
721[number]: primitive-types.html#numeric-types
722
723Just like `read_line()`, our call to `parse()` could cause an error. What if
724our string contained `A👍%`? There’d be no way to convert that to a number. As
725such, we’ll do the same thing we did with `read_line()`: use the `ok()` and
726`expect()` methods to crash if there’s an error.
727
728Let’s try our program out!
729
730```bash
731$ cargo run
d9579d0f 732 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
bd371182
AL
733 Running `target/guessing_game`
734Guess the number!
735The secret number is: 58
736Please input your guess.
737 76
738You guessed: 76
739Too big!
740```
741
742Nice! You can see I even added spaces before my guess, and it still figured
743out that I guessed 76. Run the program a few times, and verify that guessing
744the number works, as well as guessing a number too small.
745
746Now we’ve got most of the game working, but we can only make one guess. Let’s
747change that by adding loops!
748
749# Looping
750
751The `loop` keyword gives us an infinite loop. Let’s add that in:
752
753```rust,ignore
754extern crate rand;
755
756use std::io;
757use std::cmp::Ordering;
758use rand::Rng;
759
760fn main() {
761 println!("Guess the number!");
762
763 let secret_number = rand::thread_rng().gen_range(1, 101);
764
765 println!("The secret number is: {}", secret_number);
766
767 loop {
768 println!("Please input your guess.");
769
770 let mut guess = String::new();
771
772 io::stdin().read_line(&mut guess)
773 .ok()
774 .expect("failed to read line");
775
776 let guess: u32 = guess.trim().parse()
777 .ok()
778 .expect("Please type a number!");
779
780 println!("You guessed: {}", guess);
781
782 match guess.cmp(&secret_number) {
783 Ordering::Less => println!("Too small!"),
784 Ordering::Greater => println!("Too big!"),
785 Ordering::Equal => println!("You win!"),
786 }
787 }
788}
789```
790
791And try it out. But wait, didn’t we just add an infinite loop? Yup. Remember
792our discussion about `parse()`? If we give a non-number answer, we’ll `return`
793and quit. Observe:
794
795```bash
796$ cargo run
d9579d0f 797 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
bd371182
AL
798 Running `target/guessing_game`
799Guess the number!
800The secret number is: 59
801Please input your guess.
80245
803You guessed: 45
804Too small!
805Please input your guess.
80660
807You guessed: 60
808Too big!
809Please input your guess.
81059
811You guessed: 59
812You win!
813Please input your guess.
814quit
815thread '<main>' panicked at 'Please type a number!'
816```
817
818Ha! `quit` actually quits. As does any other non-number input. Well, this is
819suboptimal to say the least. First, let’s actually quit when you win the game:
820
821```rust,ignore
822extern crate rand;
823
824use std::io;
825use std::cmp::Ordering;
826use rand::Rng;
827
828fn main() {
829 println!("Guess the number!");
830
831 let secret_number = rand::thread_rng().gen_range(1, 101);
832
833 println!("The secret number is: {}", secret_number);
834
835 loop {
836 println!("Please input your guess.");
837
838 let mut guess = String::new();
839
840 io::stdin().read_line(&mut guess)
841 .ok()
842 .expect("failed to read line");
843
844 let guess: u32 = guess.trim().parse()
845 .ok()
846 .expect("Please type a number!");
847
848 println!("You guessed: {}", guess);
849
850 match guess.cmp(&secret_number) {
851 Ordering::Less => println!("Too small!"),
852 Ordering::Greater => println!("Too big!"),
853 Ordering::Equal => {
854 println!("You win!");
855 break;
856 }
857 }
858 }
859}
860```
861
862By adding the `break` line after the `You win!`, we’ll exit the loop when we
863win. Exiting the loop also means exiting the program, since it’s the last
864thing in `main()`. We have just one more tweak to make: when someone inputs a
865non-number, we don’t want to quit, we just want to ignore it. We can do that
866like this:
867
868```rust,ignore
869extern crate rand;
870
871use std::io;
872use std::cmp::Ordering;
873use rand::Rng;
874
875fn main() {
876 println!("Guess the number!");
877
878 let secret_number = rand::thread_rng().gen_range(1, 101);
879
880 println!("The secret number is: {}", secret_number);
881
882 loop {
883 println!("Please input your guess.");
884
885 let mut guess = String::new();
886
887 io::stdin().read_line(&mut guess)
888 .ok()
889 .expect("failed to read line");
890
891 let guess: u32 = match guess.trim().parse() {
892 Ok(num) => num,
893 Err(_) => continue,
894 };
895
896 println!("You guessed: {}", guess);
897
898 match guess.cmp(&secret_number) {
899 Ordering::Less => println!("Too small!"),
900 Ordering::Greater => println!("Too big!"),
901 Ordering::Equal => {
902 println!("You win!");
903 break;
904 }
905 }
906 }
907}
908```
909
910These are the lines that changed:
911
912```rust,ignore
913let guess: u32 = match guess.trim().parse() {
914 Ok(num) => num,
915 Err(_) => continue,
916};
917```
918
919This is how you generally move from ‘crash on error’ to ‘actually handle the
920error’, by switching from `ok().expect()` to a `match` statement. The `Result`
921returned by `parse()` is an enum just like `Ordering`, but in this case, each
922variant has some data associated with it: `Ok` is a success, and `Err` is a
923failure. Each contains more information: the successful parsed integer, or an
924error type. In this case, we `match` on `Ok(num)`, which sets the inner value
925of the `Ok` to the name `num`, and then we just return it on the right-hand
926side. In the `Err` case, we don’t care what kind of error it is, so we just
927use `_` instead of a name. This ignores the error, and `continue` causes us
928to go to the next iteration of the `loop`.
929
930Now we should be good! Let’s try:
931
932```bash
933$ cargo run
d9579d0f 934 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
bd371182
AL
935 Running `target/guessing_game`
936Guess the number!
937The secret number is: 61
938Please input your guess.
93910
940You guessed: 10
941Too small!
942Please input your guess.
94399
944You guessed: 99
945Too big!
946Please input your guess.
947foo
948Please input your guess.
94961
950You guessed: 61
951You win!
952```
953
954Awesome! With one tiny last tweak, we have finished the guessing game. Can you
955think of what it is? That’s right, we don’t want to print out the secret
956number. It was good for testing, but it kind of ruins the game. Here’s our
957final source:
958
959```rust,ignore
960extern crate rand;
961
962use std::io;
963use std::cmp::Ordering;
964use rand::Rng;
965
966fn main() {
967 println!("Guess the number!");
968
969 let secret_number = rand::thread_rng().gen_range(1, 101);
970
971 loop {
972 println!("Please input your guess.");
973
974 let mut guess = String::new();
975
976 io::stdin().read_line(&mut guess)
977 .ok()
978 .expect("failed to read line");
979
980 let guess: u32 = match guess.trim().parse() {
981 Ok(num) => num,
982 Err(_) => continue,
983 };
984
985 println!("You guessed: {}", guess);
986
987 match guess.cmp(&secret_number) {
988 Ordering::Less => println!("Too small!"),
989 Ordering::Greater => println!("Too big!"),
990 Ordering::Equal => {
991 println!("You win!");
992 break;
993 }
994 }
995 }
996}
997```
998
999# Complete!
1000
1001At this point, you have successfully built the Guessing Game! Congratulations!
1002
1003This first project showed you a lot: `let`, `match`, methods, associated
1004functions, using external crates, and more. Our next project will show off
1005even more.