4.6Boolean values

Last updated June 11, 2026

Do you like asparagus? Whatever your answer, it has a shape: yes or no, with no third option and no fraction. Programs are full of values shaped like that (is the file open, did the guess match, has the player lost), and Rust gives the shape a type: bool, with exactly two values, the literals true and false.

fn main() {
    let lights_on = true;
    let door_locked = false;
    println!("{lights_on} {door_locked}");
}
true false

Note that printing a bool prints the word, which sounds unremarkable until you learn that C++ prints 1 and 0 unless you ask nicely. A bool occupies one byte (lesson 4.1's size_of told you so), making it Rust's smallest type, and the one your programs will consult most often.

Bools have a dedicated operator: !, logical NOT, which flips the value. !true is false, and !lights_on is "the opposite of whatever lights_on is." (Its colleagues AND and OR arrive in lesson 6.5.)

Where bools actually come from

You'll type the literals occasionally, but most bools are born from questions. The comparison operators ask the questions: == (equal?), != (not equal?), <, >, <=, >=. Each produces a bool:

fn main() {
    let score = 87;
    let passed = score >= 60;
    let perfect = score == 100;
    println!("passed: {passed}");
    println!("perfect: {perfect}");
    println!("not perfect: {}", !perfect);
}
passed: true
perfect: false
not perfect: true

(87 clears the bar and misses perfection, a result many of us can confirm from experience.)

(Chapter 6 gives the comparison operators their full lesson; this chapter uses them gently, mostly so the next lesson has questions to ask.)

Functions that answer yes/no questions return bool, and the convention is to name them like questions: is_empty, has_won, is_equal. You can write one already with chapter 2 skills:

fn is_even(n: i32) -> bool {
    n % 2 == 0
}

fn main() {
    println!("{}", is_even(10));
    println!("{}", is_even(7));
}
true
false

(% gives the remainder after division, as seen in lesson 2.4; a number is even exactly when dividing by 2 leaves nothing.) The tail expression is a comparison, the comparison is a bool, and the bool is the return value: no if required, a small elegance worth imitating.

There is no truthiness

In many languages, non-bool values get drafted into yes/no service: C++ treats any non-zero number as "true," Python extends the idea to empty strings and lists, and every such language has a chapter of folklore about the surprises ("why is "0" truthy but 0 falsy?"). The term of art is truthiness, and Rust has none:

fn main() {
    let count = 1;
    if count {
        println!("got some");
    }
}
error[E0308]: mismatched types
 --> src/main.rs:3:8
  |
3 |     if count {
  |        ^^^^^ expected `bool`, found integer

(A one-lesson preview of if, fully introduced next lesson.) An integer is not a bool, not even 0 or 1, and no value of any other type is secretly "true." Where a C++ programmer writes if (count), hoping readers know it means "non-zero," a Rust programmer writes what they mean: if count != 0, or if count > 0, which aren't the same question, and the language just made you notice that.

Key insight

"No truthiness" is the same design reflex you saw with implicit conversions: where a convenience blurs meaning, Rust deletes the convenience and keeps the meaning. The two keystrokes you save with if (count) are repaid in code where every condition states its actual question.

Quiz time

Question #1

What does this print?

fn main() {
    let a = 5;
    let b = 10;
    println!("{}", a < b);
    println!("{}", !(a < b));
    println!("{}", a != 5);
}
Show solution
true
false
false

5 is less than 10 (true), the ! flips it, and 5 is in fact 5, so a != 5 is false.

Question #2

Predict the compiler error:

fn main() {
    let logged_in = 1;
    if logged_in {
        println!("welcome back");
    }
}
Show solution

E0308 at the condition: expected bool, found integer. logged_in is an i32 (integer literal default), and integers don't pass for bools. The deeper fix is making the variable what it claims to be: let logged_in = true;.

Question #3

Write a function is_valid_percentage(n: i32) -> bool that's true when n is between 0 and 100 inclusive. (You'll want to wait for lesson 6.5's AND operator... or realize you can do it today with what's on this page and a little nesting. Either answer teaches you something.)

Show solution

The lesson-6.5 version will be n >= 0 && n <= 100. With today's toolkit only, one honest workaround:

fn is_valid_percentage(n: i32) -> bool {
    if n < 0 {
        return false;
    }
    n <= 100
}

(Using if a lesson early; consider it a warm-up lap.) If you wrote the && version because you've seen it elsewhere: also fine, and lesson 6.5 will formalize it.

You now have values that answer questions. Next lesson, programs finally get to act on the answers, and Rust's version of if comes with a twist you've been prepared for since lesson 1.11.