Skip to content

Control Flow

if / else: an expression, produces a value

Section titled “if / else: an expression, produces a value”
let grade = if score >= 90 {
"A"
} else if score >= 80 {
"B"
} else {
"F"
}

An if without else is only valid where a Void value is acceptable.

if let checks whether a value matches a pattern and, if so, binds the pattern’s variables in the then-block. It is the idiomatic way to handle a single variant without writing an exhaustive match.

// Basic: execute only when the Option is Some
if let Some(user) = findUser(42) {
debug user
}
// With else
let name = if let Some(user) = findUser(42) {
user.name
} else {
"anonymous"
}
// Works for any sum type, not just Option/Result
type ApiResponse { Success(data: String), Loading, Failed(error: String) }
if let Success(data:) = response {
process(data)
}
// Chaining
if let Circle(radius: r) = shape {
debug r
} else if let Square(side: s) = shape {
debug s
} else {
debug "other"
}

Scoping: Pattern bindings are scoped to the then-block only. They are not visible in the else branch or after the if let expression.

When to use each construct:

ConstructIntentOn mismatch
matchHandle all variantsN/A (exhaustive)
if letConditionally handle one variantBranches or skips
let assertAssert a specific variantPanics

Valid patterns: VariantPat, TuplePat, IdentPat, WildcardPat. LiteralPat, ListPat, and OrPat are not valid (use match for those).

A block’s value is its trailing expression. Without a trailing expression it evaluates to Void.

let result = {
let x = 5
x * x
}
fn divide(
a: Int,
b: Int,
): Result<Int, String> {
if b == 0 { return Error("division by zero") }
Ok(a / b)
}