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