Frontend Labs
⋯

5. Functions, statements, and the unit and never types

// Parameter and return types are ALWAYS written; inference stays inside function bodies.
fn area(w: u32, h: u32) -> u32 {
    w * h // no semicolon: this is the return value
}

fn log(msg: &str) {          // no `-> T` means the return type is `()`, the unit type
    eprintln!("[log] {msg}");
}

fn fail(msg: &str) -> ! {    // `!` is the NEVER type: this function never returns
    panic!("fatal: {msg}");
}

fn main() {
    log("starting");
    let a = area(3, 4);
    // Because `!` converts to any type, diverging calls fit in any expression:
    let b: u32 = if a > 0 { a } else { fail("zero area") };
    println!("{b}");
}

Statements end in ; and produce (). Expressions produce values. The most common beginner error is a stray semicolon on the last line of a function:

// DOES NOT COMPILE
fn area(w: u32, h: u32) -> u32 {
    w * h;   // statement, so the body evaluates to ()
}
fn main() { println!("{}", area(1, 2)); }
error[E0308]: mismatched types
  |     fn area(w: u32, h: u32) -> u32 {
  |        ----                    ^^^ expected `u32`, found `()`
  |         w * h;
  |              - help: remove this semicolon to return this value

Rust has no function overloading and no default arguments. Use different names (new, with_capacity), Option parameters, or a builder (Ch 62).


Generated from real-life-rust-guide.md · 8 Oct 2026 16:36