3 Okay! We've got the basics of Rust down. Let's write a bigger program.
5 For our first project, we'll implement a classic beginner programming problem:
6 the guessing game. Here's how it works: Our program will generate a random
7 integer between one and a hundred. It will then prompt us to enter a guess.
8 Upon entering our guess, it will tell us if we're too low or too high. Once we
9 guess correctly, it will congratulate us. Sound good?
13 Let's set up a new project. Go to your projects directory. Remember how we
14 had to create our directory structure and a `Cargo.toml` for `hello_world`? Cargo
15 has a command that does that for us. Let's give it a shot:
19 $ cargo new guessing_game --bin
23 We pass the name of our project to `cargo new`, and then the `--bin` flag,
24 since we're making a binary, rather than a library.
26 Check out the generated `Cargo.toml`:
31 name = "guessing_game"
33 authors = ["Your Name <you@example.com>"]
36 Cargo gets this information from your environment. If it's not correct, go ahead
39 Finally, Cargo generated a "Hello, world!" for us. Check out `src/main.rs`:
43 println!("Hello, world!")
47 Let's try compiling what Cargo gave us:
51 Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
54 Excellent! Open up your `src/main.rs` again. We'll be writing all of
55 our code in this file. We'll talk about multiple-file projects later on in the
58 Before we move on, let me show you one more Cargo command: `run`. `cargo run`
59 is kind of like `cargo build`, but it also then runs the produced executable.
64 Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
65 Running `target/guessing_game`
69 Great! The `run` command comes in handy when you need to rapidly iterate on a project.
70 Our game is just such a project, we need to quickly test each iteration before moving on to the next one.
74 Let's get to it! The first thing we need to do for our guessing game is
75 allow our player to input a guess. Put this in your `src/main.rs`:
81 println!("Guess the number!");
83 println!("Please input your guess.");
85 let input = io::stdin().read_line()
87 .expect("Failed to read line");
89 println!("You guessed: {}", input);
93 You've seen this code before, when we talked about standard input. We
94 import the `std::io` module with `use`, and then our `main` function contains
95 our program's logic. We print a little message announcing the game, ask the
96 user to input a guess, get their input, and then print it out.
98 Because we talked about this in the section on standard I/O, I won't go into
99 more details here. If you need a refresher, go re-read that section.
101 ## Generating a secret number
103 Next, we need to generate a secret number. To do that, we need to use Rust's
104 random number generation, which we haven't talked about yet. Rust includes a
105 bunch of interesting functions in its standard library. If you need a bit of
106 code, it's possible that it's already been written for you! In this case,
107 we do know that Rust has random number generation, but we don't know how to
110 Enter the docs. Rust has a page specifically to document the standard library.
111 You can find that page [here](../std/index.html). There's a lot of information on
112 that page, but the best part is the search bar. Right up at the top, there's
113 a box that you can enter in a search term. The search is pretty primitive
114 right now, but is getting better all the time. If you type "random" in that
115 box, the page will update to [this one](../std/index.html?search=random). The very
116 first result is a link to [`std::rand::random`](../std/rand/fn.random.html). If we
117 click on that result, we'll be taken to its documentation page.
119 This page shows us a few things: the type signature of the function, some
120 explanatory text, and then an example. Let's try to modify our code to add in the
121 `random` function and see what happens:
128 println!("Guess the number!");
130 let secret_number = (rand::random() % 100) + 1; // secret_number: i32
132 println!("The secret number is: {}", secret_number);
134 println!("Please input your guess.");
136 let input = io::stdin().read_line()
138 .expect("Failed to read line");
141 println!("You guessed: {}", input);
145 The first thing we changed was to `use std::rand`, as the docs
146 explained. We then added in a `let` expression to create a variable binding
147 named `secret_number`, and we printed out its result.
149 Also, you may wonder why we are using `%` on the result of `rand::random()`.
150 This operator is called *modulo*, and it returns the remainder of a division.
151 By taking the modulo of the result of `rand::random()`, we're limiting the
152 values to be between 0 and 99. Then, we add one to the result, making it from 1
153 to 100. Using modulo can give you a very, very small bias in the result, but
154 for this example, it is not important.
156 Let's try to compile this using `cargo build`:
160 Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
161 src/main.rs:7:26: 7:34 error: the type of this value must be known in this context
162 src/main.rs:7 let secret_number = (rand::random() % 100) + 1;
164 error: aborting due to previous error
167 It didn't work! Rust says "the type of this value must be known in this
168 context." What's up with that? Well, as it turns out, `rand::random()` can
169 generate many kinds of random values, not just integers. And in this case, Rust
170 isn't sure what kind of value `random()` should generate. So we have to help
171 it. With number literals, we can just add an `i32` onto the end to tell Rust they're
172 integers, but that does not work with functions. There's a different syntax,
173 and it looks like this:
176 rand::random::<i32>();
179 This says "please give me a random `i32` value." We can change our code to use
187 println!("Guess the number!");
189 let secret_number = (rand::random::<i32>() % 100) + 1;
191 println!("The secret number is: {}", secret_number);
193 println!("Please input your guess.");
195 let input = io::stdin().read_line()
197 .expect("Failed to read line");
200 println!("You guessed: {}", input);
204 Try running our new program a few times:
208 Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
209 Running `target/guessing_game`
211 The secret number is: 7
212 Please input your guess.
215 $ ./target/guessing_game
217 The secret number is: 83
218 Please input your guess.
221 $ ./target/guessing_game
223 The secret number is: -29
224 Please input your guess.
229 Wait. Negative 29? We wanted a number between one and a hundred! We have two
230 options here: we can either ask `random()` to generate an unsigned integer, which
231 can only be positive, or we can use the `abs()` function. Let's go with the
232 unsigned integer approach. If we want a random positive number, we should ask for
233 a random positive number. Our code looks like this now:
240 println!("Guess the number!");
242 let secret_number = (rand::random::<uint>() % 100u) + 1u;
244 println!("The secret number is: {}", secret_number);
246 println!("Please input your guess.");
248 let input = io::stdin().read_line()
250 .expect("Failed to read line");
253 println!("You guessed: {}", input);
261 Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
262 Running `target/guessing_game`
264 The secret number is: 57
265 Please input your guess.
270 Great! Next up: let's compare our guess to the secret guess.
274 If you remember, earlier in the guide, we made a `cmp` function that compared
275 two numbers. Let's add that in, along with a `match` statement to compare our
276 guess to the secret number:
281 use std::cmp::Ordering;
284 println!("Guess the number!");
286 let secret_number = (rand::random::<uint>() % 100u) + 1u;
288 println!("The secret number is: {}", secret_number);
290 println!("Please input your guess.");
292 let input = io::stdin().read_line()
294 .expect("Failed to read line");
297 println!("You guessed: {}", input);
299 match cmp(input, secret_number) {
300 Ordering::Less => println!("Too small!"),
301 Ordering::Greater => println!("Too big!"),
302 Ordering::Equal => println!("You win!"),
306 fn cmp(a: i32, b: i32) -> Ordering {
307 if a < b { Ordering::Less }
308 else if a > b { Ordering::Greater }
309 else { Ordering::Equal }
313 If we try to compile, we'll get some errors:
317 Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
318 src/main.rs:20:15: 20:20 error: mismatched types: expected `i32` but found `collections::string::String` (expected i32 but found struct collections::string::String)
319 src/main.rs:20 match cmp(input, secret_number) {
321 src/main.rs:20:22: 20:35 error: mismatched types: expected `i32` but found `uint` (expected i32 but found uint)
322 src/main.rs:20 match cmp(input, secret_number) {
324 error: aborting due to 2 previous errors
327 This often happens when writing Rust programs, and is one of Rust's greatest
328 strengths. You try out some code, see if it compiles, and Rust tells you that
329 you've done something wrong. In this case, our `cmp` function works on integers,
330 but we've given it unsigned integers. In this case, the fix is easy, because
331 we wrote the `cmp` function! Let's change it to take `uint`s:
336 use std::cmp::Ordering;
339 println!("Guess the number!");
341 let secret_number = (rand::random::<uint>() % 100u) + 1u;
343 println!("The secret number is: {}", secret_number);
345 println!("Please input your guess.");
347 let input = io::stdin().read_line()
349 .expect("Failed to read line");
352 println!("You guessed: {}", input);
354 match cmp(input, secret_number) {
355 Ordering::Less => println!("Too small!"),
356 Ordering::Greater => println!("Too big!"),
357 Ordering::Equal => println!("You win!"),
361 fn cmp(a: uint, b: uint) -> Ordering {
362 if a < b { Ordering::Less }
363 else if a > b { Ordering::Greater }
364 else { Ordering::Equal }
368 And try compiling again:
372 Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
373 src/main.rs:20:15: 20:20 error: mismatched types: expected `uint` but found `collections::string::String` (expected uint but found struct collections::string::String)
374 src/main.rs:20 match cmp(input, secret_number) {
376 error: aborting due to previous error
379 This error is similar to the last one: we expected to get a `uint`, but we got
380 a `String` instead! That's because our `input` variable is coming from the
381 standard input, and you can guess anything. Try it:
384 $ ./target/guessing_game
386 The secret number is: 73
387 Please input your guess.
392 Oops! Also, you'll note that we just ran our program even though it didn't compile.
393 This works because the older version we did successfully compile was still lying
394 around. Gotta be careful!
396 Anyway, we have a `String`, but we need a `uint`. What to do? Well, there's
400 let input = io::stdin().read_line()
402 .expect("Failed to read line");
403 let input_num: Option<uint> = input.parse();
406 The `parse` function takes in a `&str` value and converts it into something.
407 We tell it what kind of something with a type hint. Remember our type hint with
408 `random()`? It looked like this:
411 rand::random::<uint>();
414 There's an alternate way of providing a hint too, and that's declaring the type
418 let x: uint = rand::random();
421 In this case, we say `x` is a `uint` explicitly, so Rust is able to properly
422 tell `random()` what to generate. In a similar fashion, both of these work:
425 let input_num = "5".parse::<uint>(); // input_num: Option<uint>
426 let input_num: Option<uint> = "5".parse(); // input_num: Option<uint>
429 Anyway, with us now converting our input to a number, our code looks like this:
434 use std::cmp::Ordering;
437 println!("Guess the number!");
439 let secret_number = (rand::random::<uint>() % 100u) + 1u;
441 println!("The secret number is: {}", secret_number);
443 println!("Please input your guess.");
445 let input = io::stdin().read_line()
447 .expect("Failed to read line");
448 let input_num: Option<uint> = input.parse();
450 println!("You guessed: {}", input_num);
452 match cmp(input_num, secret_number) {
453 Ordering::Less => println!("Too small!"),
454 Ordering::Greater => println!("Too big!"),
455 Ordering::Equal => println!("You win!"),
459 fn cmp(a: uint, b: uint) -> Ordering {
460 if a < b { Ordering::Less }
461 else if a > b { Ordering::Greater }
462 else { Ordering::Equal }
470 Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
471 src/main.rs:22:15: 22:24 error: mismatched types: expected `uint` but found `core::option::Option<uint>` (expected uint but found enum core::option::Option)
472 src/main.rs:22 match cmp(input_num, secret_number) {
474 error: aborting due to previous error
477 Oh yeah! Our `input_num` has the type `Option<uint>`, rather than `uint`. We
478 need to unwrap the Option. If you remember from before, `match` is a great way
479 to do that. Try this code:
484 use std::cmp::Ordering;
487 println!("Guess the number!");
489 let secret_number = (rand::random::<uint>() % 100u) + 1u;
491 println!("The secret number is: {}", secret_number);
493 println!("Please input your guess.");
495 let input = io::stdin().read_line()
497 .expect("Failed to read line");
498 let input_num: Option<uint> = input.parse();
500 let num = match input_num {
503 println!("Please input a number!");
509 println!("You guessed: {}", num);
511 match cmp(num, secret_number) {
512 Ordering::Less => println!("Too small!"),
513 Ordering::Greater => println!("Too big!"),
514 Ordering::Equal => println!("You win!"),
518 fn cmp(a: uint, b: uint) -> Ordering {
519 if a < b { Ordering::Less }
520 else if a > b { Ordering::Greater }
521 else { Ordering::Equal }
525 We use a `match` to either give us the `uint` inside of the `Option`, or else
526 print an error message and return. Let's give this a shot:
530 Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
531 Running `target/guessing_game`
533 The secret number is: 17
534 Please input your guess.
536 Please input a number!
539 Uh, what? But we did!
541 ... actually, we didn't. See, when you get a line of input from `stdin()`,
542 you get all the input. Including the `\n` character from you pressing Enter.
543 Therefore, `parse()` sees the string `"5\n"` and says "nope, that's not a
544 number; there's non-number stuff in there!" Luckily for us, `&str`s have an easy
545 method we can use defined on them: `trim()`. One small modification, and our
546 code looks like this:
551 use std::cmp::Ordering;
554 println!("Guess the number!");
556 let secret_number = (rand::random::<uint>() % 100u) + 1u;
558 println!("The secret number is: {}", secret_number);
560 println!("Please input your guess.");
562 let input = io::stdin().read_line()
564 .expect("Failed to read line");
565 let input_num: Option<uint> = input.trim().parse();
567 let num = match input_num {
570 println!("Please input a number!");
576 println!("You guessed: {}", num);
578 match cmp(num, secret_number) {
579 Ordering::Less => println!("Too small!"),
580 Ordering::Greater => println!("Too big!"),
581 Ordering::Equal => println!("You win!"),
585 fn cmp(a: uint, b: uint) -> Ordering {
586 if a < b { Ordering::Less }
587 else if a > b { Ordering::Greater }
588 else { Ordering::Equal }
596 Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
597 Running `target/guessing_game`
599 The secret number is: 58
600 Please input your guess.
606 Nice! You can see I even added spaces before my guess, and it still figured
607 out that I guessed 76. Run the program a few times, and verify that guessing
608 the number works, as well as guessing a number too small.
610 The Rust compiler helped us out quite a bit there! This technique is called
611 "leaning on the compiler", and it's often useful when working on some code.
612 Let the error messages help guide you towards the correct types.
614 Now we've got most of the game working, but we can only make one guess. Let's
615 change that by adding loops!
619 As we already discussed, the `loop` keyword gives us an infinite loop.
625 use std::cmp::Ordering;
628 println!("Guess the number!");
630 let secret_number = (rand::random::<uint>() % 100u) + 1u;
632 println!("The secret number is: {}", secret_number);
636 println!("Please input your guess.");
638 let input = io::stdin().read_line()
640 .expect("Failed to read line");
641 let input_num: Option<uint> = input.trim().parse();
643 let num = match input_num {
646 println!("Please input a number!");
652 println!("You guessed: {}", num);
654 match cmp(num, secret_number) {
655 Ordering::Less => println!("Too small!"),
656 Ordering::Greater => println!("Too big!"),
657 Ordering::Equal => println!("You win!"),
662 fn cmp(a: uint, b: uint) -> Ordering {
663 if a < b { Ordering::Less }
664 else if a > b { Ordering::Greater }
665 else { Ordering::Equal }
669 And try it out. But wait, didn't we just add an infinite loop? Yup. Remember
670 that `return`? If we give a non-number answer, we'll `return` and quit. Observe:
674 Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
675 Running `target/guessing_game`
677 The secret number is: 59
678 Please input your guess.
682 Please input your guess.
686 Please input your guess.
690 Please input your guess.
692 Please input a number!
695 Ha! `quit` actually quits. As does any other non-number input. Well, this is
696 suboptimal to say the least. First, let's actually quit when you win the game:
701 use std::cmp::Ordering;
704 println!("Guess the number!");
706 let secret_number = (rand::random::<uint>() % 100u) + 1u;
708 println!("The secret number is: {}", secret_number);
712 println!("Please input your guess.");
714 let input = io::stdin().read_line()
716 .expect("Failed to read line");
717 let input_num: Option<uint> = input.trim().parse();
719 let num = match input_num {
722 println!("Please input a number!");
728 println!("You guessed: {}", num);
730 match cmp(num, secret_number) {
731 Ordering::Less => println!("Too small!"),
732 Ordering::Greater => println!("Too big!"),
734 println!("You win!");
741 fn cmp(a: uint, b: uint) -> Ordering {
742 if a < b { Ordering::Less }
743 else if a > b { Ordering::Greater }
744 else { Ordering::Equal }
748 By adding the `return` line after the `You win!`, we'll exit the program when
749 we win. We have just one more tweak to make: when someone inputs a non-number,
750 we don't want to quit, we just want to ignore it. Change that `return` to
757 use std::cmp::Ordering;
760 println!("Guess the number!");
762 let secret_number = (rand::random::<uint>() % 100u) + 1u;
764 println!("The secret number is: {}", secret_number);
768 println!("Please input your guess.");
770 let input = io::stdin().read_line()
772 .expect("Failed to read line");
773 let input_num: Option<uint> = input.trim().parse();
775 let num = match input_num {
778 println!("Please input a number!");
784 println!("You guessed: {}", num);
786 match cmp(num, secret_number) {
787 Ordering::Less => println!("Too small!"),
788 Ordering::Greater => println!("Too big!"),
790 println!("You win!");
797 fn cmp(a: uint, b: uint) -> Ordering {
798 if a < b { Ordering::Less }
799 else if a > b { Ordering::Greater }
800 else { Ordering::Equal }
804 Now we should be good! Let's try:
808 Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
809 Running `target/guessing_game`
811 The secret number is: 61
812 Please input your guess.
816 Please input your guess.
820 Please input your guess.
822 Please input a number!
823 Please input your guess.
829 Awesome! With one tiny last tweak, we have finished the guessing game. Can you
830 think of what it is? That's right, we don't want to print out the secret number.
831 It was good for testing, but it kind of ruins the game. Here's our final source:
836 use std::cmp::Ordering;
839 println!("Guess the number!");
841 let secret_number = (rand::random::<uint>() % 100u) + 1u;
845 println!("Please input your guess.");
847 let input = io::stdin().read_line()
849 .expect("Failed to read line");
850 let input_num: Option<uint> = input.trim().parse();
852 let num = match input_num {
855 println!("Please input a number!");
861 println!("You guessed: {}", num);
863 match cmp(num, secret_number) {
864 Ordering::Less => println!("Too small!"),
865 Ordering::Greater => println!("Too big!"),
867 println!("You win!");
874 fn cmp(a: uint, b: uint) -> Ordering {
875 if a < b { Ordering::Less }
876 else if a > b { Ordering::Greater }
877 else { Ordering::Equal }
883 At this point, you have successfully built the Guessing Game! Congratulations!
885 You've now learned the basic syntax of Rust. All of this is relatively close to
886 various other programming languages you have used in the past. These
887 fundamental syntactical and semantic elements will form the foundation for the
888 rest of your Rust education.
890 Now that you're an expert at the basics, it's time to learn about some of
891 Rust's more unique features.