3 Let’s learn some Rust! For our first project, we’ll implement a classic
4 beginner programming problem: the guessing game. Here’s how it works: Our
5 program will generate a random integer between one and a hundred. It will then
6 prompt us to enter a guess. Upon entering our guess, it will tell us if we’re
7 too low or too high. Once we guess correctly, it will congratulate us. Sounds
10 Along the way, we’ll learn a little bit about Rust. The next chapter, ‘Syntax
11 and Semantics’, will dive deeper into each part.
15 Let’s set up a new project. Go to your projects directory. Remember how we had
16 to create our directory structure and a `Cargo.toml` for `hello_world`? Cargo
17 has a command that does that for us. Let’s give it a shot:
21 $ cargo new guessing_game --bin
22 Created binary (application) `guessing_game` project
26 We pass the name of our project to `cargo new`, and then the `--bin` flag,
27 since we’re making a binary, rather than a library.
29 Check out the generated `Cargo.toml`:
34 name = "guessing_game"
36 authors = ["Your Name <you@example.com>"]
39 Cargo gets this information from your environment. If it’s not correct, go ahead
42 Finally, Cargo generated a ‘Hello, world!’ for us. Check out `src/main.rs`:
46 println!("Hello, world!");
50 Let’s try compiling what Cargo gave us:
54 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
55 Finished debug [unoptimized + debuginfo] target(s) in 0.53 secs
58 Excellent! Open up your `src/main.rs` again. We’ll be writing all of
59 our code in this file.
61 Remember the `run` command from last chapter? Try it out again here:
65 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
66 Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
67 Running `target/debug/guessing_game`
71 Great! Our game is just the kind of project `run` is good for: we need
72 to quickly test each iteration before moving on to the next one.
76 Let’s get to it! The first thing we need to do for our guessing game is
77 allow our player to input a guess. Put this in your `src/main.rs`:
83 println!("Guess the number!");
85 println!("Please input your guess.");
87 let mut guess = String::new();
89 io::stdin().read_line(&mut guess)
90 .expect("Failed to read line");
92 println!("You guessed: {}", guess);
96 There’s a lot here! Let’s go over it, bit by bit.
102 We’ll need to take user input, and then print the result as output. As such, we
103 need the `io` library from the standard library. Rust only imports a few things
104 by default into every program, [the ‘prelude’][prelude]. If it’s not in the
105 prelude, you’ll have to `use` it directly. There is also a second ‘prelude’, the
106 [`io` prelude][ioprelude], which serves a similar function: you import it, and it
107 imports a number of useful, `io`-related things.
109 [prelude]: ../std/prelude/index.html
110 [ioprelude]: ../std/io/prelude/index.html
116 As you’ve seen before, the `main()` function is the entry point into your
117 program. The `fn` syntax declares a new function, the `()`s indicate that
118 there are no arguments, and `{` starts the body of the function. Because
119 we didn’t include a return type, it’s assumed to be `()`, an empty
122 [tuples]: primitive-types.html#tuples
125 println!("Guess the number!");
127 println!("Please input your guess.");
130 We previously learned that `println!()` is a [macro][macros] that
131 prints a [string][strings] to the screen.
133 [macros]: macros.html
134 [strings]: strings.html
137 let mut guess = String::new();
140 Now we’re getting interesting! There’s a lot going on in this little line.
141 The first thing to notice is that this is a [let statement][let], which is
142 used to create ‘variable bindings’. They take this form:
148 [let]: variable-bindings.html
150 This will create a new binding named `foo`, and bind it to the value `bar`. In
151 many languages, this is called a ‘variable’, but Rust’s variable bindings have
152 a few tricks up their sleeves.
154 For example, they’re [immutable][immutable] by default. That’s why our example
155 uses `mut`: it makes a binding mutable, rather than immutable. `let` doesn’t
156 take a name on the left hand side of the assignment, it actually accepts a
157 ‘[pattern][patterns]’. We’ll use patterns later. It’s easy enough
161 let foo = 5; // `foo` is immutable.
162 let mut bar = 5; // `bar` is mutable.
165 [immutable]: mutability.html
166 [patterns]: patterns.html
168 Oh, and `//` will start a comment, until the end of the line. Rust ignores
169 everything in [comments][comments].
171 [comments]: comments.html
173 So now we know that `let mut guess` will introduce a mutable binding named
174 `guess`, but we have to look at the other side of the `=` for what it’s
175 bound to: `String::new()`.
177 `String` is a string type, provided by the standard library. A
178 [`String`][string] is a growable, UTF-8 encoded bit of text.
180 [string]: ../std/string/struct.String.html
182 The `::new()` syntax uses `::` because this is an ‘associated function’ of
183 a particular type. That is to say, it’s associated with `String` itself,
184 rather than a particular instance of a `String`. Some languages call this a
187 This function is named `new()`, because it creates a new, empty `String`.
188 You’ll find a `new()` function on many types, as it’s a common name for making
189 a new value of some kind.
194 io::stdin().read_line(&mut guess)
195 .expect("Failed to read line");
198 That’s a lot more! Let’s go bit-by-bit. The first line has two parts. Here’s
205 Remember how we `use`d `std::io` on the first line of the program? We’re now
206 calling an associated function on it. If we didn’t `use std::io`, we could
207 have written this line as `std::io::stdin()`.
209 This particular function returns a handle to the standard input for your
210 terminal. More specifically, a [std::io::Stdin][iostdin].
212 [iostdin]: ../std/io/struct.Stdin.html
214 The next part will use this handle to get input from the user:
217 .read_line(&mut guess)
220 Here, we call the [`read_line()`][read_line] method on our handle.
221 [Methods][method] are like associated functions, but are only available on a
222 particular instance of a type, rather than the type itself. We’re also passing
223 one argument to `read_line()`: `&mut guess`.
225 [read_line]: ../std/io/struct.Stdin.html#method.read_line
226 [method]: method-syntax.html
228 Remember how we bound `guess` above? We said it was mutable. However,
229 `read_line` doesn’t take a `String` as an argument: it takes a `&mut String`.
230 Rust has a feature called ‘[references][references]’, which allows you to have
231 multiple references to one piece of data, which can reduce copying. References
232 are a complex feature, as one of Rust’s major selling points is how safe and
233 easy it is to use references. We don’t need to know a lot of those details to
234 finish our program right now, though. For now, all we need to know is that
235 like `let` bindings, references are immutable by default. Hence, we need to
236 write `&mut guess`, rather than `&guess`.
238 Why does `read_line()` take a mutable reference to a string? Its job is
239 to take what the user types into standard input, and place that into a
240 string. So it takes that string as an argument, and in order to add
241 the input, it needs to be mutable.
243 [references]: references-and-borrowing.html
245 But we’re not quite done with this line of code, though. While it’s
246 a single line of text, it’s only the first part of the single logical line of
250 .expect("Failed to read line");
253 When you call a method with the `.foo()` syntax, you may introduce a newline
254 and other whitespace. This helps you split up long lines. We _could_ have
258 io::stdin().read_line(&mut guess).expect("failed to read line");
261 But that gets hard to read. So we’ve split it up, two lines for two method
262 calls. We already talked about `read_line()`, but what about `expect()`? Well,
263 we already mentioned that `read_line()` puts what the user types into the `&mut
264 String` we pass it. But it also returns a value: in this case, an
265 [`io::Result`][ioresult]. Rust has a number of types named `Result` in its
266 standard library: a generic [`Result`][result], and then specific versions for
267 sub-libraries, like `io::Result`.
269 [ioresult]: ../std/io/type.Result.html
270 [result]: ../std/result/enum.Result.html
272 The purpose of these `Result` types is to encode error handling information.
273 Values of the `Result` type, like any type, have methods defined on them. In
274 this case, `io::Result` has an [`expect()` method][expect] that takes a value
275 it’s called on, and if it isn’t a successful one, [`panic!`][panic]s with a
276 message you passed it. A `panic!` like this will cause our program to crash,
277 displaying the message.
279 [expect]: ../std/result/enum.Result.html#method.expect
280 [panic]: error-handling.html
282 If we do not call `expect()`, our program will compile, but
287 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
288 warning: unused result which must be used, #[warn(unused_must_use)] on by default
291 10 | io::stdin().read_line(&mut guess);
294 Finished debug [unoptimized + debuginfo] target(s) in 0.42 secs
297 Rust warns us that we haven’t used the `Result` value. This warning comes from
298 a special annotation that `io::Result` has. Rust is trying to tell you that
299 you haven’t handled a possible error. The right way to suppress the error is
300 to actually write error handling. Luckily, if we want to crash if there’s
301 a problem, we can use `expect()`. If we can recover from the
302 error somehow, we’d do something else, but we’ll save that for a future
305 There’s only one line of this first example left:
308 println!("You guessed: {}", guess);
312 This prints out the string we saved our input in. The `{}`s are a placeholder,
313 and so we pass it `guess` as an argument. If we had multiple `{}`s, we would
314 pass multiple arguments:
320 println!("x and y: {} and {}", x, y);
325 Anyway, that’s the tour. We can run what we have with `cargo run`:
329 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
330 Finished debug [unoptimized + debuginfo] target(s) in 0.44 secs
331 Running `target/debug/guessing_game`
333 Please input your guess.
338 All right! Our first part is done: we can get input from the keyboard,
339 and then print it back out.
341 # Generating a secret number
343 Next, we need to generate a secret number. Rust does not yet include random
344 number functionality in its standard library. The Rust team does, however,
345 provide a [`rand` crate][randcrate]. A ‘crate’ is a package of Rust code.
346 We’ve been building a ‘binary crate’, which is an executable. `rand` is a
347 ‘library crate’, which contains code that’s intended to be used with other
350 [randcrate]: https://crates.io/crates/rand
352 Using external crates is where Cargo really shines. Before we can write
353 the code using `rand`, we need to modify our `Cargo.toml`. Open it up, and
354 add these few lines at the bottom:
362 The `[dependencies]` section of `Cargo.toml` is like the `[package]` section:
363 everything that follows it is part of it, until the next section starts.
364 Cargo uses the dependencies section to know what dependencies on external
365 crates you have, and what versions you require. In this case, we’ve specified version `0.3.0`,
366 which Cargo understands to be any release that’s compatible with this specific version.
367 Cargo understands [Semantic Versioning][semver], which is a standard for writing version
368 numbers. A bare number like above is actually shorthand for `^0.3.0`,
369 meaning "anything compatible with 0.3.0".
370 If we wanted to use only `0.3.0` exactly, we could say `rand="=0.3.0"`
371 (note the two equal signs).
372 We could also use a range of versions.
373 [Cargo’s documentation][cargodoc] contains more details.
375 [semver]: http://semver.org
376 [cargodoc]: http://doc.crates.io/specifying-dependencies.html
378 Now, without changing any of our code, let’s build our project:
382 Updating registry `https://github.com/rust-lang/crates.io-index`
383 Downloading rand v0.3.14
384 Downloading libc v0.2.17
385 Compiling libc v0.2.17
386 Compiling rand v0.3.14
387 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
388 Finished debug [unoptimized + debuginfo] target(s) in 5.88 secs
391 (You may see different versions, of course.)
393 Lots of new output! Now that we have an external dependency, Cargo fetches the
394 latest versions of everything from the registry, which is a copy of data from
395 [Crates.io][cratesio]. Crates.io is where people in the Rust ecosystem
396 post their open source Rust projects for others to use.
398 [cratesio]: https://crates.io
400 After updating the registry, Cargo checks our `[dependencies]` and downloads
401 any we don’t have yet. In this case, while we only said we wanted to depend on
402 `rand`, we’ve also grabbed a copy of `libc`. This is because `rand` depends on
403 `libc` to work. After downloading them, it compiles them, and then compiles
406 If we run `cargo build` again, we’ll get different output:
410 Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
413 That’s right, nothing was done! Cargo knows that our project has been built, and that
414 all of its dependencies are built, and so there’s no reason to do all that
415 stuff. With nothing to do, it simply exits. If we open up `src/main.rs` again,
416 make a trivial change, and then save it again, we’ll only see two lines:
420 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
421 Finished debug [unoptimized + debuginfo] target(s) in 0.45 secs
424 So, we told Cargo we wanted any `0.3.x` version of `rand`, and so it fetched the latest
425 version at the time this was written, `v0.3.14`. But what happens when next
426 week, version `v0.3.15` comes out, with an important bugfix? While getting
427 bugfixes is important, what if `0.3.15` contains a regression that breaks our
430 The answer to this problem is the `Cargo.lock` file you’ll now find in your
431 project directory. When you build your project for the first time, Cargo
432 figures out all of the versions that fit your criteria, and then writes them
433 to the `Cargo.lock` file. When you build your project in the future, Cargo
434 will see that the `Cargo.lock` file exists, and then use that specific version
435 rather than do all the work of figuring out versions again. This lets you
436 have a repeatable build automatically. In other words, we’ll stay at `0.3.14`
437 until we explicitly upgrade, and so will anyone who we share our code with,
438 thanks to the lock file.
440 What about when we _do_ want to use `v0.3.15`? Cargo has another command,
441 `update`, which says ‘ignore the lock, figure out all the latest versions that
442 fit what we’ve specified. If that works, write those versions out to the lock
443 file’. But, by default, Cargo will only look for versions larger than `0.3.0`
444 and smaller than `0.4.0`. If we want to move to `0.4.x`, we’d have to update
445 the `Cargo.toml` directly. When we do, the next time we `cargo build`, Cargo
446 will update the index and re-evaluate our `rand` requirements.
448 There’s a lot more to say about [Cargo][doccargo] and [its
449 ecosystem][doccratesio], but for now, that’s all we need to know. Cargo makes
450 it really easy to re-use libraries, and so Rustaceans tend to write smaller
451 projects which are assembled out of a number of sub-packages.
453 [doccargo]: http://doc.crates.io
454 [doccratesio]: http://doc.crates.io/crates-io.html
456 Let’s get on to actually _using_ `rand`. Here’s our next step:
465 println!("Guess the number!");
467 let secret_number = rand::thread_rng().gen_range(1, 101);
469 println!("The secret number is: {}", secret_number);
471 println!("Please input your guess.");
473 let mut guess = String::new();
475 io::stdin().read_line(&mut guess)
476 .expect("failed to read line");
478 println!("You guessed: {}", guess);
482 The first thing we’ve done is change the first line. It now says
483 `extern crate rand`. Because we declared `rand` in our `[dependencies]`, we
484 can use `extern crate` to let Rust know we’ll be making use of it. This also
485 does the equivalent of a `use rand;` as well, so we can make use of anything
486 in the `rand` crate by prefixing it with `rand::`.
488 Next, we added another `use` line: `use rand::Rng`. We’re going to use a
489 method in a moment, and it requires that `Rng` be in scope to work. The basic
490 idea is this: methods are defined on something called ‘traits’, and for the
491 method to work, it needs the trait to be in scope. For more about the
492 details, read the [traits][traits] section.
494 [traits]: traits.html
496 There are two other lines we added, in the middle:
499 let secret_number = rand::thread_rng().gen_range(1, 101);
501 println!("The secret number is: {}", secret_number);
504 We use the `rand::thread_rng()` function to get a copy of the random number
505 generator, which is local to the particular [thread][concurrency] of execution
506 we’re in. Because we `use rand::Rng`’d above, it has a `gen_range()` method
507 available. This method takes two arguments, and generates a number between
508 them. It’s inclusive on the lower bound, but exclusive on the upper bound,
509 so we need `1` and `101` to get a number ranging from one to a hundred.
511 [concurrency]: concurrency.html
513 The second line prints out the secret number. This is useful while
514 we’re developing our program, so we can easily test it out. But we’ll be
515 deleting it for the final version. It’s not much of a game if it prints out
516 the answer when you start it up!
518 Try running our new program a few times:
522 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
523 Finished debug [unoptimized + debuginfo] target(s) in 0.55 secs
524 Running `target/debug/guessing_game`
526 The secret number is: 7
527 Please input your guess.
531 Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
532 Running `target/debug/guessing_game`
534 The secret number is: 83
535 Please input your guess.
540 Great! Next up: comparing our guess to the secret number.
544 Now that we’ve got user input, let’s compare our guess to the secret number.
545 Here’s our next step, though it doesn’t quite compile yet:
551 use std::cmp::Ordering;
555 println!("Guess the number!");
557 let secret_number = rand::thread_rng().gen_range(1, 101);
559 println!("The secret number is: {}", secret_number);
561 println!("Please input your guess.");
563 let mut guess = String::new();
565 io::stdin().read_line(&mut guess)
566 .expect("failed to read line");
568 println!("You guessed: {}", guess);
570 match guess.cmp(&secret_number) {
571 Ordering::Less => println!("Too small!"),
572 Ordering::Greater => println!("Too big!"),
573 Ordering::Equal => println!("You win!"),
578 A few new bits here. The first is another `use`. We bring a type called
579 `std::cmp::Ordering` into scope. Then, five new lines at the bottom that use
583 match guess.cmp(&secret_number) {
584 Ordering::Less => println!("Too small!"),
585 Ordering::Greater => println!("Too big!"),
586 Ordering::Equal => println!("You win!"),
590 The `cmp()` method can be called on anything that can be compared, and it
591 takes a reference to the thing you want to compare it to. It returns the
592 `Ordering` type we `use`d earlier. We use a [`match`][match] statement to
593 determine exactly what kind of `Ordering` it is. `Ordering` is an
594 [`enum`][enum], short for ‘enumeration’, which looks like this:
606 With this definition, anything of type `Foo` can be either a
607 `Foo::Bar` or a `Foo::Baz`. We use the `::` to indicate the
608 namespace for a particular `enum` variant.
610 The [`Ordering`][ordering] `enum` has three possible variants: `Less`, `Equal`,
611 and `Greater`. The `match` statement takes a value of a type, and lets you
612 create an ‘arm’ for each possible value. Since we have three types of
613 `Ordering`, we have three arms:
616 match guess.cmp(&secret_number) {
617 Ordering::Less => println!("Too small!"),
618 Ordering::Greater => println!("Too big!"),
619 Ordering::Equal => println!("You win!"),
623 [ordering]: ../std/cmp/enum.Ordering.html
625 If it’s `Less`, we print `Too small!`, if it’s `Greater`, `Too big!`, and if
626 `Equal`, `You win!`. `match` is really useful, and is used often in Rust.
628 I did mention that this won’t quite compile yet, though. Let’s try it:
632 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
633 error[E0308]: mismatched types
634 --> src/main.rs:23:21
636 23 | match guess.cmp(&secret_number) {
637 | ^^^^^^^^^^^^^^ expected struct `std::string::String`, found integral variable
639 = note: expected type `&std::string::String`
640 = note: found type `&{integer}`
642 error: aborting due to previous error
644 error: Could not compile `guessing_game`.
646 To learn more, run the command again with --verbose.
649 Whew! This is a big error. The core of it is that we have ‘mismatched types’.
650 Rust has a strong, static type system. However, it also has type inference.
651 When we wrote `let guess = String::new()`, Rust was able to infer that `guess`
652 should be a `String`, and so it doesn’t make us write out the type. And with
653 our `secret_number`, there are a number of types which can have a value
654 between one and a hundred: `i32`, a thirty-two-bit number, or `u32`, an
655 unsigned thirty-two-bit number, or `i64`, a sixty-four-bit number or others.
656 So far, that hasn’t mattered, and so Rust defaults to an `i32`. However, here,
657 Rust doesn’t know how to compare the `guess` and the `secret_number`. They
658 need to be the same type. Ultimately, we want to convert the `String` we
659 read as input into a real number type, for comparison. We can do that
660 with two more lines. Here’s our new program:
666 use std::cmp::Ordering;
670 println!("Guess the number!");
672 let secret_number = rand::thread_rng().gen_range(1, 101);
674 println!("The secret number is: {}", secret_number);
676 println!("Please input your guess.");
678 let mut guess = String::new();
680 io::stdin().read_line(&mut guess)
681 .expect("failed to read line");
683 let guess: u32 = guess.trim().parse()
684 .expect("Please type a number!");
686 println!("You guessed: {}", guess);
688 match guess.cmp(&secret_number) {
689 Ordering::Less => println!("Too small!"),
690 Ordering::Greater => println!("Too big!"),
691 Ordering::Equal => println!("You win!"),
699 let guess: u32 = guess.trim().parse()
700 .expect("Please type a number!");
703 Wait a minute, I thought we already had a `guess`? We do, but Rust allows us
704 to ‘shadow’ the previous `guess` with a new one. This is often used in this
705 exact situation, where `guess` starts as a `String`, but we want to convert it
706 to an `u32`. Shadowing lets us re-use the `guess` name, rather than forcing us
707 to come up with two unique names like `guess_str` and `guess`, or something
710 We bind `guess` to an expression that looks like something we wrote earlier:
716 Here, `guess` refers to the old `guess`, the one that was a `String` with our
717 input in it. The `trim()` method on `String`s will eliminate any white space at
718 the beginning and end of our string. This is important, as we had to press the
719 ‘return’ key to satisfy `read_line()`. This means that if we type `5` and hit
720 return, `guess` looks like this: `5\n`. The `\n` represents ‘newline’, the
721 enter key. `trim()` gets rid of this, leaving our string with only the `5`. The
722 [`parse()` method on strings][parse] parses a string into some kind of number.
723 Since it can parse a variety of numbers, we need to give Rust a hint as to the
724 exact type of number we want. Hence, `let guess: u32`. The colon (`:`) after
725 `guess` tells Rust we’re going to annotate its type. `u32` is an unsigned,
726 thirty-two bit integer. Rust has [a number of built-in number types][number],
727 but we’ve chosen `u32`. It’s a good default choice for a small positive number.
729 [parse]: ../std/primitive.str.html#method.parse
730 [number]: primitive-types.html#numeric-types
732 Just like `read_line()`, our call to `parse()` could cause an error. What if
733 our string contained `A👍%`? There’d be no way to convert that to a number. As
734 such, we’ll do the same thing we did with `read_line()`: use the `expect()`
735 method to crash if there’s an error.
737 Let’s try our program out!
741 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
742 Finished debug [unoptimized + debuginfo] target(s) in 0.57 secs
743 Running `target/guessing_game`
745 The secret number is: 58
746 Please input your guess.
752 Nice! You can see I even added spaces before my guess, and it still figured
753 out that I guessed 76. Run the program a few times, and verify that guessing
754 the number works, as well as guessing a number too small.
756 Now we’ve got most of the game working, but we can only make one guess. Let’s
757 change that by adding loops!
761 The `loop` keyword gives us an infinite loop. Let’s add that in:
767 use std::cmp::Ordering;
771 println!("Guess the number!");
773 let secret_number = rand::thread_rng().gen_range(1, 101);
775 println!("The secret number is: {}", secret_number);
778 println!("Please input your guess.");
780 let mut guess = String::new();
782 io::stdin().read_line(&mut guess)
783 .expect("failed to read line");
785 let guess: u32 = guess.trim().parse()
786 .expect("Please type a number!");
788 println!("You guessed: {}", guess);
790 match guess.cmp(&secret_number) {
791 Ordering::Less => println!("Too small!"),
792 Ordering::Greater => println!("Too big!"),
793 Ordering::Equal => println!("You win!"),
799 And try it out. But wait, didn’t we just add an infinite loop? Yup. Remember
800 our discussion about `parse()`? If we give a non-number answer, we’ll `panic!`
805 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
806 Finished debug [unoptimized + debuginfo] target(s) in 0.58 secs
807 Running `target/guessing_game`
809 The secret number is: 59
810 Please input your guess.
814 Please input your guess.
818 Please input your guess.
822 Please input your guess.
824 thread 'main' panicked at 'Please type a number!'
827 Ha! `quit` actually quits. As does any other non-number input. Well, this is
828 suboptimal to say the least. First, let’s actually quit when you win the game:
834 use std::cmp::Ordering;
838 println!("Guess the number!");
840 let secret_number = rand::thread_rng().gen_range(1, 101);
842 println!("The secret number is: {}", secret_number);
845 println!("Please input your guess.");
847 let mut guess = String::new();
849 io::stdin().read_line(&mut guess)
850 .expect("failed to read line");
852 let guess: u32 = guess.trim().parse()
853 .expect("Please type a number!");
855 println!("You guessed: {}", guess);
857 match guess.cmp(&secret_number) {
858 Ordering::Less => println!("Too small!"),
859 Ordering::Greater => println!("Too big!"),
861 println!("You win!");
869 By adding the `break` line after the `You win!`, we’ll exit the loop when we
870 win. Exiting the loop also means exiting the program, since it’s the last
871 thing in `main()`. We have only one more tweak to make: when someone inputs a
872 non-number, we don’t want to quit, we want to ignore it. We can do that
879 use std::cmp::Ordering;
883 println!("Guess the number!");
885 let secret_number = rand::thread_rng().gen_range(1, 101);
887 println!("The secret number is: {}", secret_number);
890 println!("Please input your guess.");
892 let mut guess = String::new();
894 io::stdin().read_line(&mut guess)
895 .expect("failed to read line");
897 let guess: u32 = match guess.trim().parse() {
902 println!("You guessed: {}", guess);
904 match guess.cmp(&secret_number) {
905 Ordering::Less => println!("Too small!"),
906 Ordering::Greater => println!("Too big!"),
908 println!("You win!");
916 These are the lines that changed:
919 let guess: u32 = match guess.trim().parse() {
924 This is how you generally move from ‘crash on error’ to ‘actually handle the
925 error’, by switching from `expect()` to a `match` statement. A `Result` is
926 returned by `parse()`, this is an `enum` like `Ordering`, but in this case,
927 each variant has some data associated with it: `Ok` is a success, and `Err` is a
928 failure. Each contains more information: the successfully parsed integer, or an
929 error type. In this case, we `match` on `Ok(num)`, which sets the name `num` to
930 the unwrapped `Ok` value (the integer), and then we return it on the
931 right-hand side. In the `Err` case, we don’t care what kind of error it is, so
932 we just use the catch all `_` instead of a name. This catches everything that
933 isn't `Ok`, and `continue` lets us move to the next iteration of the loop; in
934 effect, this enables us to ignore all errors and continue with our program.
936 Now we should be good! Let’s try:
940 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
941 Finished debug [unoptimized + debuginfo] target(s) in 0.57 secs
942 Running `target/guessing_game`
944 The secret number is: 61
945 Please input your guess.
949 Please input your guess.
953 Please input your guess.
955 Please input your guess.
961 Awesome! With one tiny last tweak, we have finished the guessing game. Can you
962 think of what it is? That’s right, we don’t want to print out the secret
963 number. It was good for testing, but it kind of ruins the game. Here’s our
970 use std::cmp::Ordering;
974 println!("Guess the number!");
976 let secret_number = rand::thread_rng().gen_range(1, 101);
979 println!("Please input your guess.");
981 let mut guess = String::new();
983 io::stdin().read_line(&mut guess)
984 .expect("failed to read line");
986 let guess: u32 = match guess.trim().parse() {
991 println!("You guessed: {}", guess);
993 match guess.cmp(&secret_number) {
994 Ordering::Less => println!("Too small!"),
995 Ordering::Greater => println!("Too big!"),
997 println!("You win!");
1007 This project showed you a lot: `let`, `match`, methods, associated
1008 functions, using external crates, and more.
1010 At this point, you have successfully built the Guessing Game! Congratulations!