Rust
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Ownership and Borrowing
-
Section 4: Structuring Data
-
Section 5: Collections and Error Handling
-
Section 6: Traits and Generics
-
Section 7: Concurrency
-
Section 8: Building for the Web
-
Section 9: Memory and Performance
-
Section 10: More Standard Library and Ecosystem
-
Section 11: Advanced Rust
-
Section 12: Rust for Systems and WebAssembly
-
Section 13: Tooling and Best Practices
-
Section 14: Data Structures and Algorithms in Rust
-
Section 15: Practical Projects
-
Section 16: Interview Practice
-
Section 17: std::collections In Depth
-
Section 18: std::io and std::fs In Depth
-
Section 19: std::net
-
Section 20: std::option and std::result In Depth
-
Section 21: std::iter In Depth
-
Section 22: std::sync In Depth
-
Section 23: std::string and std::str
-
Section 24: Cargo and Crates.io Ecosystem
-
Section 25: Popular Crates Ecosystem
-
Section 26: Rust Memory Model Deep Dive
-
Section 27: More Practice Exercises
-
Section 28: More Interview Practice
-
Section 29: Async Rust Deep Dive
-
Section 30: Tokio Ecosystem In Depth
-
Section 31: Error Handling Ecosystem Deep Dive
-
Section 32: Serde In Depth
-
Section 33: Web Development with Rust Deep Dive
-
Section 34: Database Access Ecosystem
-
Section 35: Rust for Embedded Systems Deep Dive
-
Section 36: Rust Macros In Depth
-
Section 37: Advanced Trait System
-
Section 38: Unsafe Rust In Depth
-
Section 39: Rust CLI Development
-
Section 40: Testing Ecosystem Deep Dive
-
Section 41: WebAssembly Deep Dive
-
Section 42: Rust Design Patterns
-
Section 43: More Data Structures in Rust
-
Section 44: Final Practice Projects
-
Section 45: Rust Performance Optimization
-
Section 46: Rust Ecosystem Tooling
-
Section 47: More Interview and Review
8: Control Flow: If/Else
I've been thinking about how to handle game logic lately, specifically for a character's health system. It's a perfect way to look at how Rust handles decision-making. Let's just dive into a scratchpad and try to build a simple status reporter.
Let's check some health
I'll start with the simplest case: I want to print a warning if the character's health drops below a certain threshold. I'll just throw this together:
let health = 75;
if health < 100 {
println!("You're wounded!");
}
That works exactly as expected. If I change health to 110, nothing happens. The code just skips the block. It's straightforward, but in a real game, "nothing happening" usually feels like a bug to the player. If they aren't wounded, they probably want to know they're healthy.
Handling the "otherwise" case
To fix that, I'll add an else block. This is my fallback. If the first condition is false, the else block takes over.
let health = 100;
if health < 100 {
println!("You're wounded!");
} else {
println!("You're feeling great!");
}
Now, whether the health is 100 or 1,000,000, the user gets feedback. But here's the problem: what if the health is 0? Right now, the program would just say "You're wounded!" because 0 is indeed less than 100. That's a pretty big logic error—dead characters aren't "wounded," they're dead.
When two options aren't enough
I need a way to check multiple specific conditions before falling back to the default. This is where else if comes in. I have to be careful with the order here, though. If I check for health < 100 first, it will catch the 0 before I can check if the character is dead.
Let me try ordering them from the most critical state to the least:
let health = 0;
if health == 0 {
println!("You have perished.");
} else if health < 20 {
println!("Critical condition!");
} else if health < 100 {
println!("You're wounded.");
} else {
println!("You're fully healed.");
}
That feels much better. Rust evaluates these top-to-bottom and stops as soon as it finds a true condition. If health is 0, it hits the first block and ignores the rest. If it's 15, it skips the first, hits the second, and exits.
Wait, this is an expression
Here is where Rust gets interesting. In many languages, if/else is just a statement—it does something, but it doesn't "become" a value. In Rust, if is an expression. This means I can use it to assign a value to a variable.
I'll try to set a status message based on the health:
let health = 50;
let status = if health == 0 {
"Dead"
} else {
"Alive"
};
println!("Character status: {}", status);
That worked. But I wondered: can I mix types? What if I return a string for one case and a number for another? Let's see what the compiler thinks of this:
let health = 50;
let status = if health == 0 {
"Dead"
} else {
0 // Returning an integer instead of a string
};
The compiler immediately yells at me. It says expected &str, found integer. This is a crucial point: because the variable status must have one consistent type, every single branch of the if/else expression must return the exact same type. You can't be "Dead" (a string) in one breath and 0 (an integer) in the next. Rust's strictness here prevents a whole category of runtime crashes you'd see in other languages.
📋 Practical Task
Build a Combat Damage Modifier
You are building a combat system where damage is modified based on the attacker's "Stamina" level. Write a program that does the following:
- Create a variable named
stamina. - Create a variable named
base_damage(e.g., 20). - Use an
if/else if/elseexpression to assign amodifiervalue (a float/f32) based on the stamina:- If
staminais 100 or more, the modifier is1.5(Critical Hit). - If
staminais between 50 and 99, the modifier is1.0(Normal Hit). - If
staminais below 50, the modifier is0.5(Weak Hit).
- If
- Calculate the final damage by multiplying
base_damageby themodifierand print the result.
There are no comments for now.