RustArena

Step 2 of 7

if is an expression

In Rust, if is an expression: it produces a value, the value of whichever block runs. So it can sit on the right side of let:

fn main() {
    let hp = 0;
    let status = if hp > 0 { "alive" } else { "defeated" };
    println!("status: {status}");

    let coins = 7;
    let bonus = if coins >= 10 { 50 } else if coins >= 5 { 20 } else { 0 };
    println!("bonus: {bonus}");
}
status: defeated
bonus: 20

This is Rust's version of the ternary operator (cond ? a : b) from C, Java and JavaScript. Rust doesn't have one, because if already does the job.

There are no semicolons inside the blocks ({ "alive" }): each block's final expression is its value, exactly like a function body. The ; goes at the end of the whole let statement.

As a function's result

A function returns its final expression, so a final if/else is the function's result. No return needed:

fn shipping_fee(order_total: u32) -> u32 {
    if order_total >= 5000 {
        0
    } else {
        499
    }
}

fn main() {
    println!("{}", shipping_fee(7500));
    println!("{}", shipping_fee(1200));
}
0
499

Compare this with the guard clauses from the Functions module. Both are idiomatic: use an if/else expression when there are a few equal alternatives, and early return for special cases that should get out of the way of the main logic.

All branches must have the same type

The result goes into one variable with one type, so every branch must produce that type:

fn main() {
    let lives = 3;
    let label = if lives > 0 { lives } else { "game over" };
    println!("{label}");
}
error[E0308]: `if` and `else` have incompatible types
 --> src/main.rs:3:47
  |
3 |     let label = if lives > 0 { lives } else { "game over" };
  |                                -----          ^^^^^^^^^^^ expected integer, found `&str`
  |                                |
  |                                expected because of this

And when if is used as a value, the else is required. Without it, what would the value be when the condition is false?

fn main() {
    let score = 40;
    let medal = if score > 90 { "gold" };
    println!("{medal}");
}
error[E0317]: `if` may be missing an `else` clause
 --> src/main.rs:3:17
  |
3 |     let medal = if score > 90 { "gold" };
  |                 ^^^^^^^^^^^^^^^^------^^
  |                 |               |
  |                 |               found here
  |                 expected `&str`, found `()`
  |
  = note: `if` expressions without `else` evaluate to `()`

Common mistakes

Your task

Write fn clamp_volume(volume: i32) -> i32 that returns 0 for anything below 0, 100 for anything above 100, and the volume itself otherwise. Make one if / else if / else expression the function's result (no return).

(In real code you'd write volume.clamp(0, 100), and clippy suggests exactly that (manual_clamp). Here you write it by hand to practice if expressions.)

Challenge 2

Fill in the blanks so an if expression chooses the label, and the program prints even.

Challenge 3

Write fn grade(score: u32) -> char that turns a test score (0 to 100) into a letter: 90 and above is 'A', 80 and above 'B', 70 and above 'C', 60 and above 'D', and below 60 'F'. Use a single if / else if / else expression, without return.

Previous: if, else if and else Next: loop and break