If-Else Statements#

if condition {
    // do something
}

if condition {
    // do something
} else {
    // do something else
}

if condition1 {
    // do something
} else if condition2 {
    // do something else
} else {
    // fallback
}

if as an Expression#

if is an expression in Rust and can return a value.

let x = if condition { 1 } else { 2 };

let message = if score >= 90 {
    "Excellent"
} else if score >= 70 {
    "Good"
} else {
    "Needs improvement"
};

if let#

if let matches a single pattern and is a concise alternative to match when only one case matters.

let some_value: Option<i32> = Some(42);

if let Some(n) = some_value {
    println!("Got: {}", n);
} else {
    println!("Got nothing");
}

// With enums
enum Status { Active, Inactive(String) }
let s = Status::Inactive(String::from("timeout"));

if let Status::Inactive(reason) = s {
    println!("Inactive because: {}", reason);
}

Match Statements#

match compares a value against a series of patterns and executes the matching arm. All arms must be exhaustive (cover all cases).

let number = 3;

match number {
    1 => println!("one"),
    2 | 3 => println!("two or three"),    // OR pattern
    4..=9 => println!("four to nine"),    // range pattern
    n if n < 0 => println!("negative: {}", n),  // guard
    _ => println!("something else"),      // catch-all
}

Match with Destructuring#

// Tuple destructuring
let pair = (0, -2);
match pair {
    (0, y) => println!("on y-axis at {}", y),
    (x, 0) => println!("on x-axis at {}", x),
    (x, y) => println!("at ({}, {})", x, y),
}

// Struct destructuring
struct Point { x: i32, y: i32 }
let p = Point { x: 1, y: 0 };

match p {
    Point { x, y: 0 } => println!("on x-axis at {}", x),
    Point { x: 0, y } => println!("on y-axis at {}", y),
    Point { x, y } => println!("at ({}, {})", x, y),
}

// Enum destructuring
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    Color(u8, u8, u8),
}

match msg {
    Message::Quit => println!("quit"),
    Message::Move { x, y } => println!("move to ({}, {})", x, y),
    Message::Write(text) => println!("write: {}", text),
    Message::Color(r, g, b) => println!("color: {}, {}, {}", r, g, b),
}

Match as an Expression#

let description = match number {
    1 => "one",
    2 => "two",
    _ => "other",
};

Loops#

loop (infinite loop)#

Runs until an explicit break. Can return a value from break.

loop {
    // do something
    if condition {
        break;
    }
}

// loop with return value
let result = loop {
    counter += 1;
    if counter == 10 {
        break counter * 2;  // returns 20
    }
};

while#

Runs as long as a condition is true.

let mut n = 0;
while n < 5 {
    println!("{}", n);
    n += 1;
}

while let#

Continues looping while a pattern matches.

let mut stack = vec![1, 2, 3];

while let Some(top) = stack.pop() {
    println!("{}", top);  // prints 3, 2, 1
}

for#

Iterates over anything that implements IntoIterator.

// Over a range
for i in 0..5 {
    println!("{}", i);  // 0, 1, 2, 3, 4
}

for i in 0..=5 {
    println!("{}", i);  // 0, 1, 2, 3, 4, 5
}

// Over a collection
let v = vec![10, 20, 30];
for item in &v {
    println!("{}", item);  // borrows items
}

// With index using enumerate
for (i, item) in v.iter().enumerate() {
    println!("{}: {}", i, item);
}

Loop Labels#

Loop labels allow break and continue to target outer loops.

'outer: for x in 0..5 {
    for y in 0..5 {
        if x == 2 && y == 2 {
            break 'outer;   // exits both loops
        }
        if y == 3 {
            continue 'outer;  // skip to next x
        }
    }
}

continue and break#

for i in 0..10 {
    if i % 2 == 0 {
        continue;   // skip even numbers
    }
    if i == 7 {
        break;      // stop at 7
    }
    println!("{}", i);  // prints 1, 3, 5
}

Troubleshooting#

IssueCauseSolution
non-exhaustive patterns in matchNot all enum variants or value ranges are coveredAdd a catch-all _ arm or cover every variant explicitly
if arms have incompatible typesEach branch of an if expression must return the same typeEnsure both branches evaluate to the same type, or use an enum/trait object
irrefutable if let pattern warningThe pattern always matches (e.g. if let x = value)Use a plain let binding instead of if let when the pattern cannot fail
Infinite loop without breakMissing or unreachable break statementAdd a break with a reachable condition, or use while with a guard
use of moved value inside a loopValue is moved in the first iteration and unavailable afterwardClone before using in the loop body, or borrow with &

Sources#