RustArena

Functions in Rust: parameters, return values and expressions

How to write Rust functions with typed parameters and return values, why the last line has no semicolon, and expressions vs statements.

A function is declared with fn, its parameters (each with a type), and a return type after ->:

fn area(width: u32, height: u32) -> u32 {
    width * height
}

fn main() {
    let a = area(4, 5);
    println!("area {a}");
}
area 20

Parameter types are always required; Rust infers types inside a function body, but never across a function's signature. That keeps every function readable on its own and makes error messages point at the right place.

The last expression is the return value

There's no return in area. In Rust, a block's value is its last expression, the part written without a semicolon. A function body is a block, so width * height is what area returns.

The difference between expressions (which produce a value) and statements (which don't) is central to Rust:

Use return value; for early exits, typically inside an if near the top of the function (a guard clause). For the normal result at the end, idiomatic Rust leaves out return; clippy flags return x; as the last line (needless_return).

Functions with no -> return the unit type (), an empty value meaning "nothing useful". fn log(msg: &str) is short for fn log(msg: &str) -> ().

Blocks and if are expressions too

fn main() {
    let score = 82;
    let grade = if score >= 90 { 'A' } else if score >= 75 { 'B' } else { 'C' };
    let bonus = {
        let base = score / 10;
        base * 2
    };
    println!("{grade} {bonus}");
}
B 16

Every branch of an if used as a value must have the same type, and there must be an else.

Common mistakes

A semicolon after the final expression is the number one beginner error:

fn area(width: u32, height: u32) -> u32 {
    width * height;
}

fn main() {
    println!("{}", area(2, 3));
}
error[E0308]: mismatched types
 --> src/main.rs:1:37
  |
1 | fn area(width: u32, height: u32) -> u32 {
  |    ----                             ^^^ expected `u32`, found `()`
  |    |
  |    implicitly returns `()` as its body has no tail or `return` expression
2 |     width * height;
  |                   - help: remove this semicolon to return this value

With the ;, the body ends in a statement, so the function would return (), not a u32. Other common ones:

Example

fn area(width: u32, height: u32) -> u32 {
    width * height
}

fn grade(score: u32) -> char {
    if score > 100 {
        return '?';
    }
    if score >= 90 {
        'A'
    } else if score >= 75 {
        'B'
    } else {
        'C'
    }
}

fn log_line(msg: &str) {
    println!("[log] {msg}");
}

fn min_max(a: i32, b: i32) -> (i32, i32) {
    if a < b { (a, b) } else { (b, a) }
}

fn main() {
    log_line("computing");
    let room = area(4, 5);
    let half = {
        let h = room / 2;
        h + 1
    };
    println!("area {room}, half plus one {half}");
    println!("grades: {} {} {} {}", grade(95), grade(80), grade(60), grade(120));
    let (lo, hi) = min_max(9, 3);
    println!("min {lo}, max {hi}");
}

Output:

[log] computing
area 20, half plus one 11
grades: A B C ?
min 3, max 9

Practice it