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).