bool ist der einfachste Typ in Rust — und gleichzeitig der mit den klarsten Abgrenzungen zu anderen Sprachen. Rust hat kein Truthy/Falsy: weder 0, noch "", noch null werden automatisch zu false. Wenn eine Bedingung einen Bool verlangt, muss sie einen Bool liefern — Punkt. Dieser Artikel zeigt den Typ in voller Breite: Literale, Größe im Speicher, die Operatoren, die wichtigsten Methoden und die zentrale Frage, wann man bool zu Integer und zurück konvertiert.

Werte und Speicher

bool hat exakt zwei Werte: true und false. Beide sind Schlüsselwörter, beide kleingeschrieben.

Rust Basics
fn main() {
    let a: bool = true;
    let b = false;
    let c = 5 > 3;             // true (Vergleichs-Operator liefert bool)
    println!("{a} {b} {c}");
}

Speichergröße: 1 Byte (8 Bit). Theoretisch genügt 1 Bit, aber CPUs adressieren Bytes — std::mem::size_of::<bool>() ist 1.

true wird intern als 1, false als 0 repräsentiert. Andere Bit-Pattern in einem bool sind undefined behavior (relevant nur bei unsafe-Code mit Raw-Pointers oder FFI).

Operatoren

Rust Boolean-Operatoren
let a = true;
let b = false;

let nicht_a   = !a;            // false
let und        = a && b;       // false  (Short-Circuit)
let oder       = a || b;       // true   (Short-Circuit)
let xor        = a ^ b;        // true   (Bitwise XOR auf bool)
let und_bit    = a & b;        // false  (Bitwise AND, kein Short-Circuit)
let oder_bit   = a | b;        // true   (Bitwise OR, kein Short-Circuit)

Zwei Familien:

  • && und || — Short-Circuit. Werten den rechten Operanden nur aus, wenn nötig. Standard für Bool-Logik.
  • & und | — Bitweise. Werten immer beide Seiten aus. Nur nutzen, wenn Seiteneffekte beider Seiten gewollt sind.

! ist die Negation. Steht vor dem Operanden (kein not-Keyword).

Kein Truthy/Falsy

Anders als Python, JavaScript oder Ruby kennt Rust kein Konzept von „truthy" und „falsy" Werten:

Rust Anders als andere Sprachen
// if 5 { ... }                  // Fehler: expected bool, found integer
// if "" { ... }                 // Fehler: expected bool, found &str
// if Some(1) { ... }            // Fehler

Bedingungen müssen exakt bool sein. Wer auf Null prüfen will: if x != 0. Wer auf leeren String prüft: if s.is_empty(). Wer ein Option auspackt: if let Some(...) = ... oder option.is_some().

Das ist verbal aufwendiger, aber leichter zu lesen — jede Bedingung sagt explizit, was sie prüft.

Hilfreiche Methoden — then und then_some

Seit Rust 1.50 bietet bool zwei sehr nützliche Methoden für funktionalen Stil:

then — Lazy Konvertierung zu Option

then(closure) liefert Some(closure()), wenn der Bool true ist, sonst None:

Rust then
fn main() {
    let user_eingeloggt = true;
    let begruessung = user_eingeloggt.then(|| String::from("Hallo!"));

    if let Some(msg) = begruessung {
        println!("{msg}");
    }
}

Die Closure läuft nur, wenn der Bool true ist — lazy. Wichtig, wenn die Konstruktion teuer ist.

then_some — Eager Konvertierung

then_some(value) ist ein Spezialfall mit bereits berechnetem Wert:

Rust then_some
fn main() {
    let aktiv = true;
    let info = aktiv.then_some("ja");   // Some("ja")

    let nicht_aktiv = false;
    let info2 = nicht_aktiv.then_some("ja");  // None
}

Vorsicht: then_some(expensive_fn()) wertet expensive_fn() immer aus, weil es ein Argument ist. Für teure Konstruktionen besser then(|| expensive_fn()).

Idiomatische Verwendung

Rust Iterator-Filter mit then_some
let zahlen: Vec<i32> = vec![1, 2, 3, 4, 5, 6];
let gerade: Vec<i32> = zahlen.iter()
    .filter_map(|&n| (n % 2 == 0).then_some(n))
    .collect();
// [2, 4, 6]

filter_map plus then_some kombiniert „filtere" und „transformiere" in einem Schritt — eines der elegantesten Patterns für bedingte Listen-Operationen.

Konvertierung zu Integer

Rust erlaubt explizites Casten bool → integer, aber nicht umgekehrt:

Rust bool zu Integer
let a = true as u8;          // 1
let b = false as i32;        // 0

// let c: bool = 1 as bool;   // Fehler — Integer kann nicht als bool gecastet werden
let d: bool = 1 == 1;        // true (über Vergleich)
let e: bool = !(0 == 0);     // false

Warum diese Asymmetrie? Weil von bool zu u8 eindeutig ist (true→1, false→0), während die Rückrichtung viele Möglichkeiten hat: ist 2 jetzt true? 42? -1? Rust verlangt eine explizite Entscheidung, die du normalerweise als Vergleich schreibst (x != 0 oder ähnlich).

Konvertierung mit From

Seit Rust 1.28 gibt es From<bool> for u8 (und andere Integer-Typen):

Rust From
let a: u8 = true.into();      // 1
let b: i32 = false.into();    // 0
let c = u8::from(true);       // 1

Funktioniert identisch zu as, ist aber Trait-basiert (also generisch verwendbar).

Bool in Ausdrücken

bool ist ein erstklassiger Wert wie jeder andere — kann in Variablen, Tupeln, Structs gespeichert werden, als Funktions-Argument übergeben, in Match-Patterns verwendet:

Rust Match auf bool
let mode = true;

match mode {
    true  => println!("Hell"),
    false => println!("Dunkel"),
}

In der Praxis ist if/else für reines Bool-Matching idiomatischer; match lohnt sich, wenn weitere Bool-Werte oder Tupel-Patterns auftauchen:

Rust Match auf Tuple of bools
let (a, b) = (true, false);

match (a, b) {
    (true,  true)  => "beide",
    (true,  false) => "nur a",
    (false, true)  => "nur b",
    (false, false) => "keiner",
};

Praxis: Wo Bools wirklich auftauchen

Feature-Flags

Klassisches Pattern: Konfigurations-Werte zur Laufzeit steuern, ob ein Code-Pfad aktiv ist.

Rust Feature-Flags
struct Config {
    new_checkout_flow: bool,
    email_notifications: bool,
    beta_features: bool,
}

impl Config {
    fn aus_env() -> Self {
        Config {
            new_checkout_flow: std::env::var("FF_NEW_CHECKOUT").is_ok(),
            email_notifications: std::env::var("FF_EMAILS").is_ok(),
            beta_features: std::env::var("FF_BETA").is_ok(),
        }
    }
}

fn checkout(config: &Config, order_id: u64) {
    if config.new_checkout_flow {
        checkout_v2(order_id);
    } else {
        checkout_v1(order_id);
    }

    // Lazy mit then: nur loggen, wenn Beta-Modus aktiv
    let _ = config.beta_features.then(|| log_beta_event(order_id));
}
# fn checkout_v1(_: u64) {}
# fn checkout_v2(_: u64) {}
# fn log_beta_event(_: u64) {}

Permission-Checks vor sensiblen Aktionen

Rust Authorization
struct User {
    id: u64,
    ist_admin: bool,
    email_verifiziert: bool,
    zwei_faktor: bool,
}

impl User {
    fn darf_admin_panel_oeffnen(&self) -> bool {
        self.ist_admin && self.email_verifiziert && self.zwei_faktor
    }

    fn darf_kommentieren(&self) -> bool {
        self.email_verifiziert
    }
}

Short-Circuit von && ist hier wichtig: wenn der User kein Admin ist, werden die folgenden Checks nicht mehr ausgewertet — bei teureren Checks (Database-Lookup) wäre das ein Performance-Faktor.

Filter-Pipeline mit then_some

filter_map mit then_some kombiniert „filtern + transformieren" elegant:

Rust Bedingte Liste
struct Order { id: u64, total_cents: u32, refunded: bool }

fn aktive_umsaetze(orders: &[Order]) -> Vec<u32> {
    orders.iter()
        .filter_map(|o| (!o.refunded).then_some(o.total_cents))
        .collect()
}

Ohne then_some bräuchte man filter + map getrennt oder ein verschachteltes if. So liest sich der Code wie ein Datenfluss-Ausdruck.

FAQ

Warum gibt es kein truthy?

Weil implizite Konvertierungen die häufigste Quelle für subtile Bugs in dynamisch typisierten Sprachen sind. „Ist 0 falsy? Was ist mit 0.0? Mit ""? Mit null? Mit undefined?" Rust verlangt explizite Bool-Werte und überlässt die Frage „wann ist etwas leer?" der konkreten API (is_empty(), is_none(), is_zero()).

Ist bool ein Integer?

Nein. true ist nicht 1, false ist nicht 0. Sie haben dieselbe Bit-Repräsentation in der CPU, aber typ-technisch sind es verschiedene Typen. Mit as kannst du konvertieren, aber let x: bool = 1; ist ein Compile-Fehler.

Warum ist bool 1 Byte und nicht 1 Bit?

CPUs adressieren Bytes, nicht Bits. Ein einzelnes Bit zu lesen, wäre langsamer (Mask-Operationen statt direktem Load). Wer wirklich 1-Bit-Felder braucht — z. B. bei kompakten Flag-Strukturen — nutzt Bit-Manipulationen auf u8 oder eine Crate wie bitflags.

Kann bool als HashMap-Key dienen?

Ja, bool implementiert Hash und Eq. Mit nur zwei möglichen Schlüsseln ist die HashMap aber meistens overkill — ein Pair von zwei Werten oder ein 2-Element-Array reichen oft.

Was bringt then_some gegenüber if?

Lesbare Method-Chains. (n > 0).then_some(n) in einer Iterator-Pipeline ist klarer als ein zwischengeschalteter if-Block. Bei einzelnen Werten ist if einfacher.

Wie schreibt man XOR auf bool?

Mit a ^ b. Rust hat keinen separaten Bool-XOR-Operator; der Bitwise-Operator funktioniert auch auf bool und ist gleichbedeutend mit „logisches XOR". Alternative: a != b (gibt das gleiche Ergebnis).

Warum gibt std::mem::size_of::() 1 zurück, aber size_of::>() auch?

Niche-Optimization. Da bool nur zwei Bit-Pattern (0 und 1) legal nutzt, hat der Compiler Platz, None als ein anderes Bit-Pattern in das gleiche Byte zu kodieren. Ein Option<bool> belegt deshalb genau 1 Byte — anders als Option<u8>, das 2 Bytes braucht.

Bool-Algebra mit any und all auf Iteratoren.

Nicht zum Bool selbst, aber wichtig: iter.any(|x| pred(x)) und iter.all(|x| pred(x)) arbeiten Bool-basiert mit Short-Circuit. any stoppt beim ersten true, all beim ersten false. Das idiomatische Pattern für „existiert ein Element, das X erfüllt?".

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Primitive Datentypen

Zur Übersicht