Why programs need decisions
Programs rarely do the same thing every time. They check a situation and act on it: show an error only if something went wrong, give a discount only if the customer qualifies. The if statement is how Rust code does this. It runs a block of code only when a condition is true.
let is_rainy: bool = true;
if is_rainy {
println!("I bring an umbrella");
}
I bring an umbrella
The syntax
An if has three parts: the keyword, a condition, and a block in curly braces.
if condition {
// statements that run when the condition is true
}
Rust differs from several other languages in two ways here:
- No parentheses around the condition. Write
if is_rainy {, notif (is_rainy) {. Parentheses are allowed, but the compiler warns that they are unnecessary. - The braces are always required. Even a one-line body needs them. There is no braceless form like
if x println!(...).
Boolean conditions
The condition must be a bool, which is either true or false. If it is true, the block runs. If it is false, the block is skipped and the program continues after the closing brace.
let am_hungry: bool = false;
if am_hungry {
println!("I have breakfast");
}
This prints nothing, since am_hungry is false.
Rust is strict about this. It never converts other types to a boolean, so a number or a string can't stand in for a condition:
let n = 5;
if n {
println!("x");
}
error[E0308]: mismatched types
expected `bool`, found integer
To test a number, compare it: if n != 0 { ... }. The comparison produces a bool.
Using a bool directly
When a variable already holds a bool, the variable alone is the condition. Writing if passed == true works but is redundant. Write if passed, and use if !passed for the opposite.
Several decisions in one program
The three decisions from everyday life become three independent if statements. Each one is checked on its own:
let is_rainy = true;
let am_hungry = false;
let am_tired = true;
if is_rainy {
println!("I bring an umbrella");
}
if am_hungry {
println!("I have breakfast");
}
if am_tired {
println!("I take a nap");
}
I bring an umbrella
I take a nap
Any number of them can run, including none.
Variables inside a block
The braces of an if also form a scope. A variable declared inside the block exists only until the closing brace:
let passed = true;
if passed {
let message = "well done";
println!("{}", message);
}
// message no longer exists here
Using message after the block is a compile error. Variables declared before the if, like passed, can be read inside the block, so a block can use everything declared around it.
The conditions of real programs usually come from comparisons and combinations of them, which the next lessons cover. The structure never changes: a bool expression, then a block.
The exercise
The starting code declares let passed: bool = true;. The lesson builds the decision in three steps:
- Write an
ifwhose condition ispassed, and open the block with{. - Inside the block, print
"Passed the test"withprintln!. - Add an
elseblock that prints"Failed". Theelsehas no condition of its own. It runs exactly when theifcondition was false.
let passed: bool = true;
if passed {
println!("Passed the test");
} else {
println!("Failed");
}
With passed set to true, this prints Passed the test. Change the value to false and it prints Failed. Exactly one of the two blocks runs, whichever way the condition goes. Writing } else { on one line is the usual Rust layout: it closes the first block and opens the second.
Reading the result
After an if finishes, the program carries on with the next line, whether the block ran or not. An if never stops the program; it only decides whether one block takes part in it. That is why the third example above can print nothing and still leave the rest of the program running normally.
Common mistakes
- Forgetting the braces. They are mandatory, so the compiler rejects an
ifwithout them. - Using
=instead of==.=assigns and==compares. In Rust,if x = 5is a compile error rather than a silent bug. - Using a non-bool condition. Integers, strings and
Optionvalues need an explicit comparison or check first. - Putting
elseon its own line after the brace. The code compiles in Rust, but the style convention is} else {. - Adding a condition to
else.elsenever takes one. For a second condition, useelse if.
Key takeaways
if condition { ... }runs the block only when the condition istrue.- The condition must be a
bool, and it needs no parentheses. - Curly braces are always required.
- An
elseblock covers every case theifdid not.
