Functions, expressions and scope
Function parameters always carry a written type — inference stops at the function boundary, which keeps error messages local and keeps public signatures readable.
The last expression in a block is its value. Leave the semicolon off and it is returned; add one and the block evaluates to `()`, the empty tuple. That single character is behind a lot of early confusion, and behind a lot of concise Rust.
Blocks are values too, so `let x = { ... };` works and any binding declared inside the block disappears at the closing brace.
The accidental semicolon
fn add(a: i32, b: i32) -> i32 {
a + b; // error[E0308]
}error[E0308]: mismatched types: expected `i32`, found `()`
Drop the semicolon so the expression becomes the return value, or write `return a + b;` explicitly.
Run it and change it
The editor below is live: edit anything and the real compiler output updates by itself.