Rust Data Types

Boolean Type

Rust's boolean type, written bool, represents a logical truth value that can be in one of two states: true or false.

Literals and Basic Usage

The keywords true and false are the only two values of type bool:

fn main() {
    let is_active = true;          // Inferred as `bool`
    let is_complete: bool = false; // Explicitly annotated as `bool`

    println!("is_active = {is_active}, is_complete = {is_complete}");
}
is_active = true, is_complete = false

Booleans are produced by comparison operators (==, !=, <, >, <=, >=), logical operators (!, &&, ||), and predicate methods across the standard library (such as .is_empty(), .contains(), .is_some(), and .is_ok()):

fn main() {
    let temperature = 22;
    let is_comfortable = temperature >= 18 && temperature <= 25;
    let text = "Rust";
    let has_text = !text.is_empty();

    println!("is_comfortable: {is_comfortable}");
    println!("has_text:       {has_text}");
}
is_comfortable: true
has_text:       true

Memory Representation and Size (1 Byte)

Although a boolean logically requires only a single bit of information (0 or 1), CPUs address memory in whole bytes. Consequently, a bool in Rust occupies 1 byte (8 bits) in memory with a 1-byte alignment:

Value Byte Representation (Hex) Binary Pattern
false 0x00 0b0000_0000
true 0x01 0b0000_0001
Invalid (Unused bit patterns) 0x02 through 0xFF (2..=255) 0b0000_0010 .. 0b1111_1111

Niche Optimization with Option<bool>

Because a valid bool only ever uses bit patterns 0 and 1, the remaining 254 byte values (2 through 255) are unused niches. The Rust compiler automatically uses one of these unused bit patterns (0x02) to represent None inside Option<bool>, so Option<bool> takes 1 byte of memory—the exact same size as a plain bool!

bool (1 byte):                  Option<bool> (also 1 byte!):
+-------------------+           +-------------------+
| 0x00 -> false     |           | 0x00 -> Some(false)|
| 0x01 -> true      |           | 0x01 -> Some(true) |
| 0x02..0xFF unused |           | 0x02 -> None       |
+-------------------+           +-------------------+
use std::mem::size_of;

fn main() {
    println!("size_of::<bool>()         = {} byte", size_of::<bool>());
    println!("size_of::<Option<bool>>() = {} byte", size_of::<Option<bool>>());
}
size_of::<bool>()         = 1 byte
size_of::<Option<bool>>() = 1 byte

Pattern Matching on bool

Because bool has only two possible values, a match expression over a bool is exhaustive as soon as it covers both true and false:

fn describe_state(online: bool) -> &'static str {
    match online {
        true => "Connected to server",
        false => "Offline mode",
    }
}

fn main() {
    println!("{}", describe_state(true));
    println!("{}", describe_state(false));
}
Connected to server
Offline mode

Omitting either true or false in a match expression fails to compile (E0004: non-exhaustive patterns).

Converting Between bool and Integers

Converting bool to an Integer (false -> 0, true -> 1)

A bool can be converted to any integer type losslessly using From::from (such as u8::from(flag) or i32::from(flag)) or the as cast operator (flag as usize):

  • false always converts to 0.
  • true always converts to 1.
fn main() {
    let flags = [true, false, true, true, false];

    // Count how many `true` values exist by converting each `bool` to `usize`
    let mut active_count: usize = 0;
    for flag in flags {
        active_count += usize::from(flag);
    }

    println!("false as u8 = {}", false as u8);
    println!("true as u8  = {}", true as u8);
    println!("Active count: {active_count}");
}
false as u8 = 0
true as u8  = 1
Active count: 3

Converting an Integer to bool

Rust forbids casting an integer to a bool with as bool. Instead, write an explicit comparison such as n != 0:

// ❌ does not compile
fn main() {
    let status_code = 1;
    let ok = status_code as bool;
}
error[E0054]: cannot cast `i32` as `bool`
 --> src/main.rs:3:14
  |
3 |     let ok = status_code as bool;
  |              ^^^^^^^^^^^^^^^^^^^ help: compare with zero instead: `status_code != 0`

error: aborting due to 1 previous error

Built-In Methods on bool: then and then_some

The bool type provides two convenient methods for turning a boolean condition directly into an Option<T> without writing an if / else block:

Method Signature Behavior
b.then_some(val) fn then_some<T>(self, t: T) -> Option<T> Eagerly evaluates val; returns Some(val) if b is true, or None if b is false
b.then(|| expr) fn then<T, F>(self, f: F) -> Option<T> Lazily runs closure f only if b is true, returning Some(f()) or None
fn main() {
    let is_member = true;
    let is_vip = false;

    let discount = is_member.then_some(10);
    let vip_badge = is_vip.then(|| String::from("Gold Star"));

    println!("discount:  {discount:?}");
    println!("vip_badge: {vip_badge:?}");
}
discount:  Some(10)
vip_badge: None

Ordering of bool Values (false < true)

Because false has the numeric representation 0 and true has the representation 1, bool implements Ord with false < true:

fn main() {
    assert!(false < true);

    let mut statuses = [true, false, true, false];
    statuses.sort();
    println!("Sorted booleans: {statuses:?}");
}
Sorted booleans: [false, false, true, true]