Rustif / else

if / else in Rust

Conditional logic is one of the most fundamental tools in any programming language. Rust's if and else are familiar in syntax but have two important differences from languages like JavaScript, Python, or C: conditions must be a bool (there is no implicit truthiness), and if is an expression that can return a value.

Basic if / else

The simplest form of a conditional checks one condition and runs a block of code when it is true, with an optional fallback for when it is false.

RUST
fn main() {
    let temperature = 28;

    if temperature > 30 {
        println!("It is hot outside.");
    } else {
        println!("The weather is pleasant.");
    }
}
The weather is pleasant.
Conditions Must Be bool — No Implicit Truthiness

This is one of the biggest differences from Python and JavaScript. In Rust, the condition of an if expression must evaluate to a bool. Rust will not treat 0 as false or a non-empty string as true — you must write the comparison explicitly.

RUST
fn main() {
    let count = 5;

    // CORRECT — explicit comparison produces a bool
    if count > 0 {
        println!("count is positive");
    }

    // WRONG — this does not compile in Rust
    // if count {  // ERROR: expected bool, found integer
    //     println!("this fails");
    // }

    let name = String::from("Alice");

    // CORRECT — .is_empty() returns a bool
    if !name.is_empty() {
        println!("Hello, {}!", name);
    }

    // WRONG — strings are not truthy in Rust
    // if name {  // ERROR: expected bool, found struct String
    //     println!("this also fails");
    // }
}
Note
This strictness is intentional. Implicit truthiness is a common source of bugs in other languages (for example, accidentally checking a pointer instead of its value). Rust makes the intent explicit at every if-condition.
else if Chains

You can chain multiple conditions together with else if. Rust evaluates them in order and runs the first block whose condition is true.

RUST
fn main() {
    let score = 72;

    if score >= 90 {
        println!("Grade: A");
    } else if score >= 80 {
        println!("Grade: B");
    } else if score >= 70 {
        println!("Grade: C");
    } else if score >= 60 {
        println!("Grade: D");
    } else {
        println!("Grade: F");
    }
}
Grade: C
Tip
When you have many `else if` branches that match on a single value, consider using a `match` expression instead — it is more readable and the compiler enforces that all cases are covered.
if as an Expression

In Rust, if is an expression — it produces a value that can be assigned to a variable, returned from a function, or used inline. This eliminates the need for ternary operators (? :) found in C, Java, and JavaScript.

RUST
fn main() {
    let condition = true;

    // if as an expression — assign the result directly
    let number = if condition { 5 } else { 10 };
    println!("number = {}", number); // number = 5

    // Equivalent to a ternary in other languages:
    // let number = condition ? 5 : 10;  (JavaScript / C / Java)

    // Use it inline in a function call
    let age = 20;
    println!("You are {}.", if age >= 18 { "an adult" } else { "a minor" });
}
All Arms Must Return the Same Type

When if is used as an expression, every branch must produce the same type. Rust is statically typed and must know at compile time what type a variable holds. If the arms return different types, the compiler will reject the code.

RUST
fn main() {
    let condition = true;

    // This is FINE — both arms are i32
    let x = if condition { 5 } else { 10 };

    // This DOES NOT COMPILE — one arm is i32, the other is &str
    // let y = if condition { 5 } else { "ten" };
    // ERROR:
    //   if and else have incompatible types
    //   expected integer, found &str
}
Warning
The compiler error "if and else have incompatible types" is one of the most common mistakes when using if-as-expression. Both the if block and the else block must evaluate to the same type.
if Without else as a Statement

When if is used as a statement (not assigned to a variable), the else branch is optional. The block implicitly returns () (the unit type), so there is no type mismatch.

RUST
fn main() {
    let logged_in = true;

    // No else needed — we only care about the true case
    if logged_in {
        println!("Welcome back!");
    }

    // The compiler infers this is a statement (returns unit), not an expression
    // so no else branch is required
}
if in Return Statements

Because if is an expression, functions can use it as their final (returned) value without writing return.

RUST
fn classify_number(n: i32) -> &'static str {
    // The if expression is the last thing in the function
    // so its value is automatically returned
    if n > 0 {
        "positive"
    } else if n < 0 {
        "negative"
    } else {
        "zero"
    }
}

fn abs_value(n: i32) -> i32 {
    if n < 0 { -n } else { n }
}

fn main() {
    println!("{}", classify_number(42));  // positive
    println!("{}", classify_number(-7));  // negative
    println!("{}", classify_number(0));   // zero
    println!("{}", abs_value(-15));       // 15
}
Combining if with let Bindings

You can use if together with let for concise conditional assignments. A common pattern is to derive a value from a condition and immediately use it.

RUST
fn main() {
    let is_weekend = true;
    let day_type = if is_weekend { "weekend" } else { "weekday" };
    println!("Today is a {}.", day_type);

    // Combining multiple conditions in one let binding
    let hour = 14;
    let greeting = if hour < 12 {
        "Good morning"
    } else if hour < 18 {
        "Good afternoon"
    } else {
        "Good evening"
    };
    println!("{}!", greeting); // Good afternoon!

    // Nested if in a let binding (keep it readable)
    let speed = 85;
    let speed_limit = 100;
    let within_limit = if speed <= speed_limit { true } else { false };
    // Simpler: let within_limit = speed <= speed_limit;
    println!("Within limit: {}", within_limit);
}
Tip
For boolean results, skip the `if` entirely: `let within_limit = speed <= speed_limit;` is cleaner than `if speed <= speed_limit { true } else { false }`.
Nested if Expressions

You can nest if expressions inside one another. Be mindful of readability — deeply nested ifs are usually a sign that the logic should be refactored into a separate function or a match expression.

RUST
fn can_buy_alcohol(age: u32, has_id: bool) -> bool {
    if age >= 18 {
        if has_id {
            true
        } else {
            println!("Age OK but no ID presented.");
            false
        }
    } else {
        println!("Under age.");
        false
    }
}

fn main() {
    println!("{}", can_buy_alcohol(20, true));  // true
    println!("{}", can_buy_alcohol(20, false)); // false (prints warning)
    println!("{}", can_buy_alcohol(16, true));  // false (prints warning)
}
Note
The example above can be flattened with a single `if` and `&&`: `if age >= 18 && has_id { true } else { false }` — which further simplifies to just `age >= 18 && has_id`.
Practical Examples

Here are a few real-world patterns that combine if/else with Rust's type system.

RUST
fn divide(a: f64, b: f64) -> Option<f64> {
    if b == 0.0 {
        None       // cannot divide by zero
    } else {
        Some(a / b)
    }
}

fn fizzbuzz(n: u32) -> String {
    if n % 15 == 0 {
        String::from("FizzBuzz")
    } else if n % 3 == 0 {
        String::from("Fizz")
    } else if n % 5 == 0 {
        String::from("Buzz")
    } else {
        n.to_string()
    }
}

fn bmi_category(bmi: f64) -> &'static str {
    if bmi < 18.5 {
        "Underweight"
    } else if bmi < 25.0 {
        "Normal weight"
    } else if bmi < 30.0 {
        "Overweight"
    } else {
        "Obese"
    }
}

fn main() {
    println!("{:?}", divide(10.0, 3.0)); // Some(3.3333...)
    println!("{:?}", divide(10.0, 0.0)); // None

    for i in 1..=15 {
        print!("{} ", fizzbuzz(i));
    }
    println!();
    // 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz

    println!("{}", bmi_category(22.4)); // Normal weight
}
Comparison with Other Languages

Language

Implicit truthiness?

if as expression?

Ternary operator?

Rust

No — bool only

Yes

No (use if/else)

JavaScript

Yes (0, "", null...)

No

Yes (? :)

Python

Yes (0, [], None...)

Yes (ternary only)

Yes (x if c else y)

Java

No — bool only

No

Yes (? :)

C

Yes (0 = false)

No

Yes (? :)

Go

No — bool only

No

No

Success
You now understand Rust's conditional expressions. Key takeaways: conditions must be a bool (no implicit truthiness), if is an expression that produces a value, all branches must return the same type when used as an expression, and you can use if directly in return positions without the return keyword.