Installing Rust on Your Computer
Up until now, we've been running code in the Rust Playground. Starting with this module, we're going to build programs directly on your computer!
Run this command in your terminal to install Rust:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
On Windows, download the installer from rustup.rs.
Once the installation is done, let's verify it worked:
rustc --version
cargo --version
If you see version numbers, you're all set!
Cargo — Rust's All-in-One Tool
Cargo is Rust's build system and package manager. It handles project creation, building, running, and managing external libraries — all in one tool.
Let's create a new project:
cargo new guessing_game
cd guessing_game
This creates the following folder structure:
guessing_game/
├── Cargo.toml # Project configuration file
└── src/
└── main.rs # Source code file
Open src/main.rs and you'll see it already has a "Hello, world!" program. Try running it with cargo run!
cargo run
Working Code: Number Guessing Game
Now let's build the actual game. First, we need to add the rand crate to generate random numbers. A crate is a library made by someone else.
cargo add rand
This command automatically adds rand to your Cargo.toml.
Paste the code below into src/main.rs and run it with cargo run!
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("Number Guessing Game!");
let secret = rand::thread_rng().gen_range(1..=100);
loop {
println!("Enter a number (1-100):");
let mut guess = String::new();
io::stdin().read_line(&mut guess).unwrap();
let guess: i32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("Please enter a valid number!");
continue;
}
};
match guess.cmp(&secret) {
Ordering::Less => println!("Too low!"),
Ordering::Greater => println!("Too high!"),
Ordering::Equal => {
println!("You got it!");
break;
}
}
}
}
When you run it, you'll be prompted to enter a number. After each guess, it tells you whether the answer is higher or lower, and it keeps going until you get it right!
Line by Line
That's a fair amount of code, right? Let's break it down piece by piece.
Step 1: Imports
use std::io;
use std::cmp::Ordering;
use rand::Rng;
use is the keyword for bringing in functionality from elsewhere.
std::io— Input/output functionalitystd::cmp::Ordering— The result of comparing two values (Less,Greater,Equal)rand::Rng— Random number generation (from the crate we added)
Step 2: Generate a Random Number
let secret = rand::thread_rng().gen_range(1..=100);
This generates a random number between 1 and 100 and stores it in secret. The 1..=100 syntax is the same range syntax we learned in the for loop module!
Step 3: Read User Input
let mut guess = String::new();
io::stdin().read_line(&mut guess).unwrap();
String::new() creates an empty string, and read_line() stores what the user types into it. unwrap() means "if there's an error, just crash the program." We'll learn proper error handling later.
Step 4: Convert String to Number
let guess: i32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("Please enter a valid number!");
continue;
}
};
What the user typed is a string. To compare it with a number, we need to convert it to i32.
trim()— Removes the newline character at the end of the inputparse()— Attempts to convert the string to a numbermatch— Branches based on the result (success isOk, failure isErr)
Notice how we declare guess again with let using the same name? That's shadowing, which we learned in Module 02! We're replacing the string guess with a numeric guess.
Step 5: Compare
match guess.cmp(&secret) {
Ordering::Less => println!("Too low!"),
Ordering::Greater => println!("Too high!"),
Ordering::Equal => {
println!("You got it!");
break;
}
}
cmp() compares two values and returns Less, Greater, or Equal. We use match to print the appropriate message for each case, and break out of the loop when the guess is correct.
"Why?" — If You've Made It This Far, You've Got the Rust Basics Down!
This program uses everything we've learned so far:
- Variables and mutability:
let,let mut - Types:
i32,String - Function calls:
println!(),read_line(),parse() - Branching:
match(a more powerful alternative to if!) - Loops:
loop+break,continue - Ranges:
1..=100
It might look complex at first, but when you break it down, it's just a combination of things you already know. In Phase 2, we'll explore concepts unique to Rust — ownership, structs, error handling, and more. Stay tuned!
Deep Dive
Cargo.toml — Exploring the project configuration file
Open Cargo.toml and you'll see something like this:
[package]
name = "guessing_game"
version = "0.1.0"
edition = "2021"
[dependencies]
rand = "0.8"
[package]— Project name, version, and Rust edition[dependencies]— List of external crates. Runningcargo add randautomatically adds entries here
Here are some frequently used Cargo commands worth knowing:
| Command | What it does |
| ----------------- | ------------------------------------------ |
| cargo new name | Create a new project |
| cargo run | Build + run (most used during development) |
| cargo build | Build only (doesn't run) |
| cargo check | Quickly check if the code compiles |
| cargo add crate | Add an external crate |
match — More powerful than if
In this game, match appears twice. match is similar to if/else if, but it requires you to handle every possible case.
fn main() {
let number = 3;
match number {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("something else"), // all other cases
}
}
_ means "everything else." We'll cover match in much more detail in Phase 2.
If you try to parse() something that isn't a number, you'll get an error. In our game, we handle this with match.
But what if we had used unwrap() instead?
// This will crash the program if the input isn't a number!
let guess: i32 = guess.trim().parse().unwrap();
If you type "abc", you'll see this error:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value:
ParseIntError { kind: InvalidDigit }'
What this means: "You tried to convert something that isn't a number into a number." Using match instead of unwrap() lets you handle errors gracefully.
Mini Project: Upgrade the Game
Once the basic game is working, try adding these features one at a time!
- Count attempts: Display how many guesses it took. Hint: Create a counter with a
mutvariable. - Range validation: If the user enters a number outside 1-100, print "Please enter a number between 1 and 100!"
- Difficulty selection: Let the player choose the range before the game starts. (e.g., 1-10, 1-100, 1-1000)
Q1. What is the Cargo command to create a new project?
- A)
cargo init project - B)
cargo new project - C)
cargo create project - D)
cargo start project
Q2. What does guess.trim().parse() do in the code below?
let guess: i32 = guess.trim().parse().unwrap();
- A) Converts the string to uppercase
- B) Removes whitespace and converts to a number
- C) Reverses the string
- D) Copies the string
Q3. What does _ mean in a match expression?
- A) It causes an error
- B) It does nothing
- C) It handles all remaining cases
- D) It stops the loop